1c609719bSwdenk /* 2c609719bSwdenk * (C) Copyright 2000 3c609719bSwdenk * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 4c609719bSwdenk * 5c609719bSwdenk * See file CREDITS for list of people who contributed to this 6c609719bSwdenk * project. 7c609719bSwdenk * 8c609719bSwdenk * This program is free software; you can redistribute it and/or 9c609719bSwdenk * modify it under the terms of the GNU General Public License as 10c609719bSwdenk * published by the Free Software Foundation; either version 2 of 11c609719bSwdenk * the License, or (at your option) any later version. 12c609719bSwdenk * 13c609719bSwdenk * This program is distributed in the hope that it will be useful, 14c609719bSwdenk * but WITHOUT ANY WARRANTY; without even the implied warranty of 15c609719bSwdenk * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16c609719bSwdenk * GNU General Public License for more details. 17c609719bSwdenk * 18c609719bSwdenk * You should have received a copy of the GNU General Public License 19c609719bSwdenk * along with this program; if not, write to the Free Software 20c609719bSwdenk * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 21c609719bSwdenk * MA 02111-1307 USA 22c609719bSwdenk */ 23c609719bSwdenk 24a6c7ad2fSwdenk /* #define DEBUG */ 25a6c7ad2fSwdenk 26c609719bSwdenk #include <common.h> 27c609719bSwdenk #include <watchdog.h> 28c609719bSwdenk #include <command.h> 29c609719bSwdenk #include <cmd_nvedit.h> 30c609719bSwdenk #include <cmd_bootm.h> 31c609719bSwdenk #include <malloc.h> 32c609719bSwdenk #if defined(CONFIG_BOOT_RETRY_TIME) && defined(CONFIG_RESET_TO_RETRY) 33c609719bSwdenk #include <cmd_boot.h> /* for do_reset() prototype */ 34c609719bSwdenk #endif 35c609719bSwdenk 36c609719bSwdenk #ifdef CFG_HUSH_PARSER 37c609719bSwdenk #include <hush.h> 38c609719bSwdenk #endif 39c609719bSwdenk 40c609719bSwdenk #define MAX_DELAY_STOP_STR 32 41c609719bSwdenk 42c609719bSwdenk static char * delete_char (char *buffer, char *p, int *colp, int *np, int plen); 43c609719bSwdenk static int parse_line (char *, char *[]); 44c609719bSwdenk #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0) 45c609719bSwdenk static int abortboot(int); 46c609719bSwdenk #endif 47c609719bSwdenk 48c609719bSwdenk #undef DEBUG_PARSER 49c609719bSwdenk 50c609719bSwdenk char console_buffer[CFG_CBSIZE]; /* console I/O buffer */ 51c609719bSwdenk 52c609719bSwdenk static char erase_seq[] = "\b \b"; /* erase sequence */ 53c609719bSwdenk static char tab_seq[] = " "; /* used to expand TABs */ 54c609719bSwdenk 55c609719bSwdenk #ifdef CONFIG_BOOT_RETRY_TIME 56c609719bSwdenk static uint64_t endtime = 0; /* must be set, default is instant timeout */ 57c609719bSwdenk static int retry_time = -1; /* -1 so can call readline before main_loop */ 58c609719bSwdenk #endif 59c609719bSwdenk 60c609719bSwdenk #define endtick(seconds) (get_ticks() + (uint64_t)(seconds) * get_tbclk()) 61c609719bSwdenk 62c609719bSwdenk #ifndef CONFIG_BOOT_RETRY_MIN 63c609719bSwdenk #define CONFIG_BOOT_RETRY_MIN CONFIG_BOOT_RETRY_TIME 64c609719bSwdenk #endif 65c609719bSwdenk 66c609719bSwdenk #ifdef CONFIG_MODEM_SUPPORT 67c609719bSwdenk int do_mdm_init = 0; 68c609719bSwdenk extern void mdm_init(void); /* defined in board.c */ 69c609719bSwdenk #endif 70c609719bSwdenk 71c609719bSwdenk /*************************************************************************** 72c609719bSwdenk * Watch for 'delay' seconds for autoboot stop or autoboot delay string. 73c609719bSwdenk * returns: 0 - no key string, allow autoboot 74c609719bSwdenk * 1 - got key string, abort 75c609719bSwdenk */ 76c609719bSwdenk #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0) 77c609719bSwdenk # if defined(CONFIG_AUTOBOOT_KEYED) 78c609719bSwdenk static __inline__ int abortboot(int bootdelay) 79c609719bSwdenk { 80c609719bSwdenk int abort = 0; 81c609719bSwdenk uint64_t etime = endtick(bootdelay); 82c609719bSwdenk struct 83c609719bSwdenk { 84c609719bSwdenk char* str; 85c609719bSwdenk u_int len; 86c609719bSwdenk int retry; 87c609719bSwdenk } 88c609719bSwdenk delaykey [] = 89c609719bSwdenk { 90c609719bSwdenk { str: getenv ("bootdelaykey"), retry: 1 }, 91c609719bSwdenk { str: getenv ("bootdelaykey2"), retry: 1 }, 92c609719bSwdenk { str: getenv ("bootstopkey"), retry: 0 }, 93c609719bSwdenk { str: getenv ("bootstopkey2"), retry: 0 }, 94c609719bSwdenk }; 95c609719bSwdenk 96c609719bSwdenk char presskey [MAX_DELAY_STOP_STR]; 97c609719bSwdenk u_int presskey_len = 0; 98c609719bSwdenk u_int presskey_max = 0; 99c609719bSwdenk u_int i; 100c609719bSwdenk 101c609719bSwdenk # ifdef CONFIG_AUTOBOOT_PROMPT 102c609719bSwdenk printf (CONFIG_AUTOBOOT_PROMPT, bootdelay); 103c609719bSwdenk # endif 104c609719bSwdenk 105c609719bSwdenk # ifdef CONFIG_AUTOBOOT_DELAY_STR 106c609719bSwdenk if (delaykey[0].str == NULL) 107c609719bSwdenk delaykey[0].str = CONFIG_AUTOBOOT_DELAY_STR; 108c609719bSwdenk # endif 109c609719bSwdenk # ifdef CONFIG_AUTOBOOT_DELAY_STR2 110c609719bSwdenk if (delaykey[1].str == NULL) 111c609719bSwdenk delaykey[1].str = CONFIG_AUTOBOOT_DELAY_STR2; 112c609719bSwdenk # endif 113c609719bSwdenk # ifdef CONFIG_AUTOBOOT_STOP_STR 114c609719bSwdenk if (delaykey[2].str == NULL) 115c609719bSwdenk delaykey[2].str = CONFIG_AUTOBOOT_STOP_STR; 116c609719bSwdenk # endif 117c609719bSwdenk # ifdef CONFIG_AUTOBOOT_STOP_STR2 118c609719bSwdenk if (delaykey[3].str == NULL) 119c609719bSwdenk delaykey[3].str = CONFIG_AUTOBOOT_STOP_STR2; 120c609719bSwdenk # endif 121c609719bSwdenk 122c609719bSwdenk for (i = 0; i < sizeof(delaykey) / sizeof(delaykey[0]); i ++) { 123c609719bSwdenk delaykey[i].len = delaykey[i].str == NULL ? 124c609719bSwdenk 0 : strlen (delaykey[i].str); 125c609719bSwdenk delaykey[i].len = delaykey[i].len > MAX_DELAY_STOP_STR ? 126c609719bSwdenk MAX_DELAY_STOP_STR : delaykey[i].len; 127c609719bSwdenk 128c609719bSwdenk presskey_max = presskey_max > delaykey[i].len ? 129c609719bSwdenk presskey_max : delaykey[i].len; 130c609719bSwdenk 131c609719bSwdenk # if DEBUG_BOOTKEYS 132c609719bSwdenk printf("%s key:<%s>\n", 133c609719bSwdenk delaykey[i].retry ? "delay" : "stop", 134c609719bSwdenk delaykey[i].str ? delaykey[i].str : "NULL"); 135c609719bSwdenk # endif 136c609719bSwdenk } 137c609719bSwdenk 138c609719bSwdenk /* In order to keep up with incoming data, check timeout only 139c609719bSwdenk * when catch up. 140c609719bSwdenk */ 141c609719bSwdenk while (!abort && get_ticks() <= etime) { 142c609719bSwdenk for (i = 0; i < sizeof(delaykey) / sizeof(delaykey[0]); i ++) { 143c609719bSwdenk if (delaykey[i].len > 0 && 144c609719bSwdenk presskey_len >= delaykey[i].len && 145c609719bSwdenk memcmp (presskey + presskey_len - delaykey[i].len, 146c609719bSwdenk delaykey[i].str, 147c609719bSwdenk delaykey[i].len) == 0) { 148c609719bSwdenk # if DEBUG_BOOTKEYS 149c609719bSwdenk printf("got %skey\n", 150c609719bSwdenk delaykey[i].retry ? "delay" : "stop"); 151c609719bSwdenk # endif 152c609719bSwdenk 153c609719bSwdenk # ifdef CONFIG_BOOT_RETRY_TIME 154c609719bSwdenk /* don't retry auto boot */ 155c609719bSwdenk if (! delaykey[i].retry) 156c609719bSwdenk retry_time = -1; 157c609719bSwdenk # endif 158c609719bSwdenk abort = 1; 159c609719bSwdenk } 160c609719bSwdenk } 161c609719bSwdenk 162c609719bSwdenk if (tstc()) { 163c609719bSwdenk if (presskey_len < presskey_max) { 164c609719bSwdenk presskey [presskey_len ++] = getc(); 165c609719bSwdenk } 166c609719bSwdenk else { 167c609719bSwdenk for (i = 0; i < presskey_max - 1; i ++) 168c609719bSwdenk presskey [i] = presskey [i + 1]; 169c609719bSwdenk 170c609719bSwdenk presskey [i] = getc(); 171c609719bSwdenk } 172c609719bSwdenk } 173c609719bSwdenk } 174c609719bSwdenk # if DEBUG_BOOTKEYS 175c609719bSwdenk if (!abort) 176c609719bSwdenk printf("key timeout\n"); 177c609719bSwdenk # endif 178c609719bSwdenk 179c609719bSwdenk return abort; 180c609719bSwdenk } 181c609719bSwdenk 182c609719bSwdenk # else /* !defined(CONFIG_AUTOBOOT_KEYED) */ 183c609719bSwdenk 184c7de829cSwdenk #ifdef CONFIG_MENUKEY 185c7de829cSwdenk static int menukey = 0; 186c7de829cSwdenk #endif 187c7de829cSwdenk 188c609719bSwdenk static __inline__ int abortboot(int bootdelay) 189c609719bSwdenk { 190c609719bSwdenk int abort = 0; 191c609719bSwdenk 192c7de829cSwdenk #ifdef CONFIG_MENUPROMPT 193c7de829cSwdenk printf(CONFIG_MENUPROMPT, bootdelay); 194c7de829cSwdenk #else 195c609719bSwdenk printf("Hit any key to stop autoboot: %2d ", bootdelay); 196c7de829cSwdenk #endif 197c609719bSwdenk 198c609719bSwdenk #if defined CONFIG_ZERO_BOOTDELAY_CHECK 199c609719bSwdenk /* 200c609719bSwdenk * Check if key already pressed 201c609719bSwdenk * Don't check if bootdelay < 0 202c609719bSwdenk */ 203c609719bSwdenk if (bootdelay >= 0) { 204c609719bSwdenk if (tstc()) { /* we got a key press */ 205c609719bSwdenk (void) getc(); /* consume input */ 206c609719bSwdenk printf ("\b\b\b 0\n"); 207c609719bSwdenk return 1; /* don't auto boot */ 208c609719bSwdenk } 209c609719bSwdenk } 210c609719bSwdenk #endif 211c609719bSwdenk 212c609719bSwdenk while (bootdelay > 0) { 213c609719bSwdenk int i; 214c609719bSwdenk 215c609719bSwdenk --bootdelay; 216c609719bSwdenk /* delay 100 * 10ms */ 217c609719bSwdenk for (i=0; !abort && i<100; ++i) { 218c609719bSwdenk if (tstc()) { /* we got a key press */ 219c609719bSwdenk abort = 1; /* don't auto boot */ 220c609719bSwdenk bootdelay = 0; /* no more delay */ 221c7de829cSwdenk # ifdef CONFIG_MENUKEY 222c7de829cSwdenk menukey = getc(); 223c7de829cSwdenk # else 224c609719bSwdenk (void) getc(); /* consume input */ 225c7de829cSwdenk # endif 226c609719bSwdenk break; 227c609719bSwdenk } 228c609719bSwdenk udelay (10000); 229c609719bSwdenk } 230c609719bSwdenk 231c609719bSwdenk printf ("\b\b\b%2d ", bootdelay); 232c609719bSwdenk } 233c609719bSwdenk 234c609719bSwdenk putc ('\n'); 235c609719bSwdenk 236c609719bSwdenk return abort; 237c609719bSwdenk } 238c609719bSwdenk # endif /* CONFIG_AUTOBOOT_KEYED */ 239c609719bSwdenk #endif /* CONFIG_BOOTDELAY >= 0 */ 240c609719bSwdenk 241c609719bSwdenk /****************************************************************************/ 242c609719bSwdenk 243c609719bSwdenk void main_loop (void) 244c609719bSwdenk { 245c609719bSwdenk #ifndef CFG_HUSH_PARSER 246c609719bSwdenk static char lastcommand[CFG_CBSIZE] = { 0, }; 247c609719bSwdenk int len; 248c609719bSwdenk int rc = 1; 249c609719bSwdenk int flag; 250c609719bSwdenk #endif 251c609719bSwdenk 252c609719bSwdenk #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0) 253c609719bSwdenk char *s; 254c609719bSwdenk int bootdelay; 255c609719bSwdenk #endif 256c609719bSwdenk #ifdef CONFIG_PREBOOT 257c609719bSwdenk char *p; 258c609719bSwdenk #endif 259c609719bSwdenk 260c609719bSwdenk #if defined(CONFIG_VFD) && defined(VFD_TEST_LOGO) 261c609719bSwdenk ulong bmp = 0; /* default bitmap */ 262c609719bSwdenk extern int trab_vfd (ulong bitmap); 263c609719bSwdenk 264c609719bSwdenk #ifdef CONFIG_MODEM_SUPPORT 265c609719bSwdenk if (do_mdm_init) 266c609719bSwdenk bmp = 1; /* alternate bitmap */ 267c609719bSwdenk #endif 268c609719bSwdenk trab_vfd (bmp); 269c609719bSwdenk #endif /* CONFIG_VFD && VFD_TEST_LOGO */ 270c609719bSwdenk 271c609719bSwdenk #ifdef CONFIG_MODEM_SUPPORT 272c609719bSwdenk debug ("DEBUG: main_loop: do_mdm_init=%d\n", do_mdm_init); 273c609719bSwdenk if (do_mdm_init) { 274c609719bSwdenk uchar *str = strdup(getenv("mdm_cmd")); 275c609719bSwdenk setenv ("preboot", str); /* set or delete definition */ 276c609719bSwdenk if (str != NULL) 277c609719bSwdenk free (str); 278c609719bSwdenk mdm_init(); /* wait for modem connection */ 279c609719bSwdenk } 280c609719bSwdenk #endif /* CONFIG_MODEM_SUPPORT */ 281c609719bSwdenk 2820587597cSstroese #ifdef CONFIG_VERSION_VARIABLE 2830587597cSstroese { 2840587597cSstroese extern char version_string[]; 2850587597cSstroese char *str = getenv("ver"); 2860587597cSstroese 2870587597cSstroese if (!str) 2880587597cSstroese setenv ("ver", version_string); /* set version variable */ 2890587597cSstroese } 2900587597cSstroese #endif /* CONFIG_VERSION_VARIABLE */ 2910587597cSstroese 292c609719bSwdenk #ifdef CFG_HUSH_PARSER 293c609719bSwdenk u_boot_hush_start (); 294c609719bSwdenk #endif 295c609719bSwdenk 296c609719bSwdenk #ifdef CONFIG_PREBOOT 297c609719bSwdenk if ((p = getenv ("preboot")) != NULL) { 298c609719bSwdenk # ifdef CONFIG_AUTOBOOT_KEYED 299c609719bSwdenk int prev = disable_ctrlc(1); /* disable Control C checking */ 300c609719bSwdenk # endif 301c609719bSwdenk 302c609719bSwdenk # ifndef CFG_HUSH_PARSER 303c609719bSwdenk run_command (p, 0); 304c609719bSwdenk # else 305c609719bSwdenk parse_string_outer(p, FLAG_PARSE_SEMICOLON | 306c609719bSwdenk FLAG_EXIT_FROM_LOOP); 307c609719bSwdenk # endif 308c609719bSwdenk 309c609719bSwdenk # ifdef CONFIG_AUTOBOOT_KEYED 310c609719bSwdenk disable_ctrlc(prev); /* restore Control C checking */ 311c609719bSwdenk # endif 312c609719bSwdenk } 313c609719bSwdenk #endif /* CONFIG_PREBOOT */ 314c609719bSwdenk 315c609719bSwdenk #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0) 316c609719bSwdenk s = getenv ("bootdelay"); 317c609719bSwdenk bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY; 318c609719bSwdenk 319a6c7ad2fSwdenk debug ("### main_loop entered: bootdelay=%d\n\n", bootdelay); 320c609719bSwdenk 321c609719bSwdenk # ifdef CONFIG_BOOT_RETRY_TIME 322c609719bSwdenk s = getenv ("bootretry"); 323c609719bSwdenk if (s != NULL) 324c609719bSwdenk retry_time = (int)simple_strtoul(s, NULL, 10); 325c609719bSwdenk else 326c609719bSwdenk retry_time = CONFIG_BOOT_RETRY_TIME; 327c609719bSwdenk if (retry_time >= 0 && retry_time < CONFIG_BOOT_RETRY_MIN) 328c609719bSwdenk retry_time = CONFIG_BOOT_RETRY_MIN; 329c609719bSwdenk # endif /* CONFIG_BOOT_RETRY_TIME */ 330c609719bSwdenk 331c609719bSwdenk s = getenv ("bootcmd"); 332a6c7ad2fSwdenk 333a6c7ad2fSwdenk debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>"); 334a6c7ad2fSwdenk 335c609719bSwdenk if (bootdelay >= 0 && s && !abortboot (bootdelay)) { 336c609719bSwdenk # ifdef CONFIG_AUTOBOOT_KEYED 337c609719bSwdenk int prev = disable_ctrlc(1); /* disable Control C checking */ 338c609719bSwdenk # endif 339c609719bSwdenk 340c609719bSwdenk # ifndef CFG_HUSH_PARSER 341c609719bSwdenk run_command (s, 0); 342c609719bSwdenk # else 343c609719bSwdenk parse_string_outer(s, FLAG_PARSE_SEMICOLON | 344c609719bSwdenk FLAG_EXIT_FROM_LOOP); 345c609719bSwdenk # endif 346c609719bSwdenk 347c609719bSwdenk # ifdef CONFIG_AUTOBOOT_KEYED 348c609719bSwdenk disable_ctrlc(prev); /* restore Control C checking */ 349c609719bSwdenk # endif 350c609719bSwdenk } 351c7de829cSwdenk 352c7de829cSwdenk # ifdef CONFIG_MENUKEY 353a6c7ad2fSwdenk if (menukey == CONFIG_MENUKEY) { 354c7de829cSwdenk s = getenv("menucmd"); 355a6c7ad2fSwdenk if (s) { 356c7de829cSwdenk # ifndef CFG_HUSH_PARSER 357c7de829cSwdenk run_command (s, bd, 0); 358c7de829cSwdenk # else 359c7de829cSwdenk parse_string_outer(s, FLAG_PARSE_SEMICOLON | 360c7de829cSwdenk FLAG_EXIT_FROM_LOOP); 361c7de829cSwdenk # endif 362c7de829cSwdenk } 363c7de829cSwdenk } 364c7de829cSwdenk #endif /* CONFIG_MENUKEY */ 365c609719bSwdenk #endif /* CONFIG_BOOTDELAY */ 366c609719bSwdenk 367c7de829cSwdenk #ifdef CONFIG_AMIGAONEG3SE 368c7de829cSwdenk { 369c7de829cSwdenk extern void video_banner(void); 370c7de829cSwdenk video_banner(); 371c7de829cSwdenk } 372c7de829cSwdenk #endif 373c7de829cSwdenk 374c609719bSwdenk /* 375c609719bSwdenk * Main Loop for Monitor Command Processing 376c609719bSwdenk */ 377c609719bSwdenk #ifdef CFG_HUSH_PARSER 378c609719bSwdenk parse_file_outer(); 379c609719bSwdenk /* This point is never reached */ 380c609719bSwdenk for (;;); 381c609719bSwdenk #else 382c609719bSwdenk for (;;) { 383c609719bSwdenk #ifdef CONFIG_BOOT_RETRY_TIME 384c609719bSwdenk if (rc >= 0) { 385c609719bSwdenk /* Saw enough of a valid command to 386c609719bSwdenk * restart the timeout. 387c609719bSwdenk */ 388c609719bSwdenk reset_cmd_timeout(); 389c609719bSwdenk } 390c609719bSwdenk #endif 391c609719bSwdenk len = readline (CFG_PROMPT); 392c609719bSwdenk 393c609719bSwdenk flag = 0; /* assume no special flags for now */ 394c609719bSwdenk if (len > 0) 395c609719bSwdenk strcpy (lastcommand, console_buffer); 396c609719bSwdenk else if (len == 0) 397c609719bSwdenk flag |= CMD_FLAG_REPEAT; 398c609719bSwdenk #ifdef CONFIG_BOOT_RETRY_TIME 399c609719bSwdenk else if (len == -2) { 400c609719bSwdenk /* -2 means timed out, retry autoboot 401c609719bSwdenk */ 402c609719bSwdenk printf("\nTimed out waiting for command\n"); 403c609719bSwdenk # ifdef CONFIG_RESET_TO_RETRY 404c609719bSwdenk /* Reinit board to run initialization code again */ 405c609719bSwdenk do_reset (NULL, 0, 0, NULL); 406c609719bSwdenk # else 407c609719bSwdenk return; /* retry autoboot */ 408c609719bSwdenk # endif 409c609719bSwdenk } 410c609719bSwdenk #endif 411c609719bSwdenk 412c609719bSwdenk if (len == -1) 413c609719bSwdenk printf ("<INTERRUPT>\n"); 414c609719bSwdenk else 415c609719bSwdenk rc = run_command (lastcommand, flag); 416c609719bSwdenk 417c609719bSwdenk if (rc <= 0) { 418c609719bSwdenk /* invalid command or not repeatable, forget it */ 419c609719bSwdenk lastcommand[0] = 0; 420c609719bSwdenk } 421c609719bSwdenk } 422c609719bSwdenk #endif /*CFG_HUSH_PARSER*/ 423c609719bSwdenk } 424c609719bSwdenk 425c609719bSwdenk /*************************************************************************** 426c609719bSwdenk * reset command line timeout to retry_time seconds 427c609719bSwdenk */ 428c609719bSwdenk #ifdef CONFIG_BOOT_RETRY_TIME 429c609719bSwdenk void reset_cmd_timeout(void) 430c609719bSwdenk { 431c609719bSwdenk endtime = endtick(retry_time); 432c609719bSwdenk } 433c609719bSwdenk #endif 434c609719bSwdenk 435c609719bSwdenk /****************************************************************************/ 436c609719bSwdenk 437c609719bSwdenk /* 438c609719bSwdenk * Prompt for input and read a line. 439c609719bSwdenk * If CONFIG_BOOT_RETRY_TIME is defined and retry_time >= 0, 440c609719bSwdenk * time out when time goes past endtime (timebase time in ticks). 441c609719bSwdenk * Return: number of read characters 442c609719bSwdenk * -1 if break 443c609719bSwdenk * -2 if timed out 444c609719bSwdenk */ 445c609719bSwdenk int readline (const char *const prompt) 446c609719bSwdenk { 447c609719bSwdenk char *p = console_buffer; 448c609719bSwdenk int n = 0; /* buffer index */ 449c609719bSwdenk int plen = 0; /* prompt length */ 450c609719bSwdenk int col; /* output column cnt */ 451c609719bSwdenk char c; 452c609719bSwdenk 453c609719bSwdenk /* print prompt */ 454c609719bSwdenk if (prompt) { 455c609719bSwdenk plen = strlen (prompt); 456c609719bSwdenk puts (prompt); 457c609719bSwdenk } 458c609719bSwdenk col = plen; 459c609719bSwdenk 460c609719bSwdenk for (;;) { 461c609719bSwdenk #ifdef CONFIG_BOOT_RETRY_TIME 462c609719bSwdenk while (!tstc()) { /* while no incoming data */ 463c609719bSwdenk if (retry_time >= 0 && get_ticks() > endtime) 464c609719bSwdenk return (-2); /* timed out */ 465c609719bSwdenk } 466c609719bSwdenk #endif 467c609719bSwdenk WATCHDOG_RESET(); /* Trigger watchdog, if needed */ 468c609719bSwdenk 469c609719bSwdenk #ifdef CONFIG_SHOW_ACTIVITY 470c609719bSwdenk while (!tstc()) { 471c609719bSwdenk extern void show_activity(int arg); 472c609719bSwdenk show_activity(0); 473c609719bSwdenk } 474c609719bSwdenk #endif 475c609719bSwdenk c = getc(); 476c609719bSwdenk 477c609719bSwdenk /* 478c609719bSwdenk * Special character handling 479c609719bSwdenk */ 480c609719bSwdenk switch (c) { 481c609719bSwdenk case '\r': /* Enter */ 482c609719bSwdenk case '\n': 483c609719bSwdenk *p = '\0'; 484c609719bSwdenk puts ("\r\n"); 485c609719bSwdenk return (p - console_buffer); 486c609719bSwdenk 487c609719bSwdenk case 0x03: /* ^C - break */ 488c609719bSwdenk console_buffer[0] = '\0'; /* discard input */ 489c609719bSwdenk return (-1); 490c609719bSwdenk 491c609719bSwdenk case 0x15: /* ^U - erase line */ 492c609719bSwdenk while (col > plen) { 493c609719bSwdenk puts (erase_seq); 494c609719bSwdenk --col; 495c609719bSwdenk } 496c609719bSwdenk p = console_buffer; 497c609719bSwdenk n = 0; 498c609719bSwdenk continue; 499c609719bSwdenk 500c609719bSwdenk case 0x17: /* ^W - erase word */ 501c609719bSwdenk p=delete_char(console_buffer, p, &col, &n, plen); 502c609719bSwdenk while ((n > 0) && (*p != ' ')) { 503c609719bSwdenk p=delete_char(console_buffer, p, &col, &n, plen); 504c609719bSwdenk } 505c609719bSwdenk continue; 506c609719bSwdenk 507c609719bSwdenk case 0x08: /* ^H - backspace */ 508c609719bSwdenk case 0x7F: /* DEL - backspace */ 509c609719bSwdenk p=delete_char(console_buffer, p, &col, &n, plen); 510c609719bSwdenk continue; 511c609719bSwdenk 512c609719bSwdenk default: 513c609719bSwdenk /* 514c609719bSwdenk * Must be a normal character then 515c609719bSwdenk */ 516c609719bSwdenk if (n < CFG_CBSIZE-2) { 517c609719bSwdenk if (c == '\t') { /* expand TABs */ 518c609719bSwdenk puts (tab_seq+(col&07)); 519c609719bSwdenk col += 8 - (col&07); 520c609719bSwdenk } else { 521c609719bSwdenk ++col; /* echo input */ 522c609719bSwdenk putc (c); 523c609719bSwdenk } 524c609719bSwdenk *p++ = c; 525c609719bSwdenk ++n; 526c609719bSwdenk } else { /* Buffer full */ 527c609719bSwdenk putc ('\a'); 528c609719bSwdenk } 529c609719bSwdenk } 530c609719bSwdenk } 531c609719bSwdenk } 532c609719bSwdenk 533c609719bSwdenk /****************************************************************************/ 534c609719bSwdenk 535c609719bSwdenk static char * delete_char (char *buffer, char *p, int *colp, int *np, int plen) 536c609719bSwdenk { 537c609719bSwdenk char *s; 538c609719bSwdenk 539c609719bSwdenk if (*np == 0) { 540c609719bSwdenk return (p); 541c609719bSwdenk } 542c609719bSwdenk 543c609719bSwdenk if (*(--p) == '\t') { /* will retype the whole line */ 544c609719bSwdenk while (*colp > plen) { 545c609719bSwdenk puts (erase_seq); 546c609719bSwdenk (*colp)--; 547c609719bSwdenk } 548c609719bSwdenk for (s=buffer; s<p; ++s) { 549c609719bSwdenk if (*s == '\t') { 550c609719bSwdenk puts (tab_seq+((*colp) & 07)); 551c609719bSwdenk *colp += 8 - ((*colp) & 07); 552c609719bSwdenk } else { 553c609719bSwdenk ++(*colp); 554c609719bSwdenk putc (*s); 555c609719bSwdenk } 556c609719bSwdenk } 557c609719bSwdenk } else { 558c609719bSwdenk puts (erase_seq); 559c609719bSwdenk (*colp)--; 560c609719bSwdenk } 561c609719bSwdenk (*np)--; 562c609719bSwdenk return (p); 563c609719bSwdenk } 564c609719bSwdenk 565c609719bSwdenk /****************************************************************************/ 566c609719bSwdenk 567c609719bSwdenk int parse_line (char *line, char *argv[]) 568c609719bSwdenk { 569c609719bSwdenk int nargs = 0; 570c609719bSwdenk 571c609719bSwdenk #ifdef DEBUG_PARSER 572c609719bSwdenk printf ("parse_line: \"%s\"\n", line); 573c609719bSwdenk #endif 574c609719bSwdenk while (nargs < CFG_MAXARGS) { 575c609719bSwdenk 576c609719bSwdenk /* skip any white space */ 577c609719bSwdenk while ((*line == ' ') || (*line == '\t')) { 578c609719bSwdenk ++line; 579c609719bSwdenk } 580c609719bSwdenk 581c609719bSwdenk if (*line == '\0') { /* end of line, no more args */ 582c609719bSwdenk argv[nargs] = NULL; 583c609719bSwdenk #ifdef DEBUG_PARSER 584c609719bSwdenk printf ("parse_line: nargs=%d\n", nargs); 585c609719bSwdenk #endif 586c609719bSwdenk return (nargs); 587c609719bSwdenk } 588c609719bSwdenk 589c609719bSwdenk argv[nargs++] = line; /* begin of argument string */ 590c609719bSwdenk 591c609719bSwdenk /* find end of string */ 592c609719bSwdenk while (*line && (*line != ' ') && (*line != '\t')) { 593c609719bSwdenk ++line; 594c609719bSwdenk } 595c609719bSwdenk 596c609719bSwdenk if (*line == '\0') { /* end of line, no more args */ 597c609719bSwdenk argv[nargs] = NULL; 598c609719bSwdenk #ifdef DEBUG_PARSER 599c609719bSwdenk printf ("parse_line: nargs=%d\n", nargs); 600c609719bSwdenk #endif 601c609719bSwdenk return (nargs); 602c609719bSwdenk } 603c609719bSwdenk 604c609719bSwdenk *line++ = '\0'; /* terminate current arg */ 605c609719bSwdenk } 606c609719bSwdenk 607c609719bSwdenk printf ("** Too many args (max. %d) **\n", CFG_MAXARGS); 608c609719bSwdenk 609c609719bSwdenk #ifdef DEBUG_PARSER 610c609719bSwdenk printf ("parse_line: nargs=%d\n", nargs); 611c609719bSwdenk #endif 612c609719bSwdenk return (nargs); 613c609719bSwdenk } 614c609719bSwdenk 615c609719bSwdenk /****************************************************************************/ 616c609719bSwdenk 617c609719bSwdenk static void process_macros (const char *input, char *output) 618c609719bSwdenk { 619c609719bSwdenk char c, prev; 620c609719bSwdenk const char *varname_start = NULL; 621c609719bSwdenk int inputcnt = strlen (input); 622c609719bSwdenk int outputcnt = CFG_CBSIZE; 623c609719bSwdenk int state = 0; /* 0 = waiting for '$' */ 624c609719bSwdenk /* 1 = waiting for '(' */ 625c609719bSwdenk /* 2 = waiting for ')' */ 626a25f862bSwdenk /* 3 = waiting for ''' */ 627c609719bSwdenk #ifdef DEBUG_PARSER 628c609719bSwdenk char *output_start = output; 629c609719bSwdenk 630c609719bSwdenk printf ("[PROCESS_MACROS] INPUT len %d: \"%s\"\n", strlen(input), input); 631c609719bSwdenk #endif 632c609719bSwdenk 633c609719bSwdenk prev = '\0'; /* previous character */ 634c609719bSwdenk 635c609719bSwdenk while (inputcnt && outputcnt) { 636c609719bSwdenk c = *input++; 637c609719bSwdenk inputcnt--; 638c609719bSwdenk 639a25f862bSwdenk if (state!=3) { 640c609719bSwdenk /* remove one level of escape characters */ 641c609719bSwdenk if ((c == '\\') && (prev != '\\')) { 642c609719bSwdenk if (inputcnt-- == 0) 643c609719bSwdenk break; 644c609719bSwdenk prev = c; 645c609719bSwdenk c = *input++; 646c609719bSwdenk } 647a25f862bSwdenk } 648c609719bSwdenk 649c609719bSwdenk switch (state) { 650c609719bSwdenk case 0: /* Waiting for (unescaped) $ */ 651a25f862bSwdenk if ((c == '\'') && (prev != '\\')) { 652a25f862bSwdenk state = 3; 653a25f862bSwdenk break; 654a25f862bSwdenk } 655c609719bSwdenk if ((c == '$') && (prev != '\\')) { 656c609719bSwdenk state++; 657c609719bSwdenk } else { 658c609719bSwdenk *(output++) = c; 659c609719bSwdenk outputcnt--; 660c609719bSwdenk } 661c609719bSwdenk break; 662c609719bSwdenk case 1: /* Waiting for ( */ 663c609719bSwdenk if (c == '(') { 664c609719bSwdenk state++; 665c609719bSwdenk varname_start = input; 666c609719bSwdenk } else { 667c609719bSwdenk state = 0; 668c609719bSwdenk *(output++) = '$'; 669c609719bSwdenk outputcnt--; 670c609719bSwdenk 671c609719bSwdenk if (outputcnt) { 672c609719bSwdenk *(output++) = c; 673c609719bSwdenk outputcnt--; 674c609719bSwdenk } 675c609719bSwdenk } 676c609719bSwdenk break; 677c609719bSwdenk case 2: /* Waiting for ) */ 678c609719bSwdenk if (c == ')') { 679c609719bSwdenk int i; 680c609719bSwdenk char envname[CFG_CBSIZE], *envval; 681c609719bSwdenk int envcnt = input-varname_start-1; /* Varname # of chars */ 682c609719bSwdenk 683c609719bSwdenk /* Get the varname */ 684c609719bSwdenk for (i = 0; i < envcnt; i++) { 685c609719bSwdenk envname[i] = varname_start[i]; 686c609719bSwdenk } 687c609719bSwdenk envname[i] = 0; 688c609719bSwdenk 689c609719bSwdenk /* Get its value */ 690c609719bSwdenk envval = getenv (envname); 691c609719bSwdenk 692c609719bSwdenk /* Copy into the line if it exists */ 693c609719bSwdenk if (envval != NULL) 694c609719bSwdenk while ((*envval) && outputcnt) { 695c609719bSwdenk *(output++) = *(envval++); 696c609719bSwdenk outputcnt--; 697c609719bSwdenk } 698c609719bSwdenk /* Look for another '$' */ 699c609719bSwdenk state = 0; 700c609719bSwdenk } 701c609719bSwdenk break; 702a25f862bSwdenk case 3: /* Waiting for ' */ 703a25f862bSwdenk if ((c == '\'') && (prev != '\\')) { 704a25f862bSwdenk state = 0; 705a25f862bSwdenk } else { 706a25f862bSwdenk *(output++) = c; 707a25f862bSwdenk outputcnt--; 708c609719bSwdenk } 709a25f862bSwdenk break; 710a25f862bSwdenk } 711c609719bSwdenk prev = c; 712c609719bSwdenk } 713c609719bSwdenk 714c609719bSwdenk if (outputcnt) 715c609719bSwdenk *output = 0; 716c609719bSwdenk 717c609719bSwdenk #ifdef DEBUG_PARSER 718c609719bSwdenk printf ("[PROCESS_MACROS] OUTPUT len %d: \"%s\"\n", 719c609719bSwdenk strlen(output_start), output_start); 720c609719bSwdenk #endif 721c609719bSwdenk } 722c609719bSwdenk 723c609719bSwdenk /**************************************************************************** 724c609719bSwdenk * returns: 725c609719bSwdenk * 1 - command executed, repeatable 726c609719bSwdenk * 0 - command executed but not repeatable, interrupted commands are 727c609719bSwdenk * always considered not repeatable 728c609719bSwdenk * -1 - not executed (unrecognized, bootd recursion or too many args) 729c609719bSwdenk * (If cmd is NULL or "" or longer than CFG_CBSIZE-1 it is 730c609719bSwdenk * considered unrecognized) 731c609719bSwdenk * 732c609719bSwdenk * WARNING: 733c609719bSwdenk * 734c609719bSwdenk * We must create a temporary copy of the command since the command we get 735c609719bSwdenk * may be the result from getenv(), which returns a pointer directly to 736c609719bSwdenk * the environment data, which may change magicly when the command we run 737c609719bSwdenk * creates or modifies environment variables (like "bootp" does). 738c609719bSwdenk */ 739c609719bSwdenk 740c609719bSwdenk int run_command (const char *cmd, int flag) 741c609719bSwdenk { 742c609719bSwdenk cmd_tbl_t *cmdtp; 743c609719bSwdenk char cmdbuf[CFG_CBSIZE]; /* working copy of cmd */ 744c609719bSwdenk char *token; /* start of token in cmdbuf */ 745c609719bSwdenk char *sep; /* end of token (separator) in cmdbuf */ 746c609719bSwdenk char finaltoken[CFG_CBSIZE]; 747c609719bSwdenk char *str = cmdbuf; 748c609719bSwdenk char *argv[CFG_MAXARGS + 1]; /* NULL terminated */ 749c609719bSwdenk int argc; 750c609719bSwdenk int repeatable = 1; 751a25f862bSwdenk int inquotes; 752c609719bSwdenk 753c609719bSwdenk #ifdef DEBUG_PARSER 754c609719bSwdenk printf ("[RUN_COMMAND] cmd[%p]=\"", cmd); 755c609719bSwdenk puts (cmd ? cmd : "NULL"); /* use puts - string may be loooong */ 756c609719bSwdenk puts ("\"\n"); 757c609719bSwdenk #endif 758c609719bSwdenk 759c609719bSwdenk clear_ctrlc(); /* forget any previous Control C */ 760c609719bSwdenk 761c609719bSwdenk if (!cmd || !*cmd) { 762c609719bSwdenk return -1; /* empty command */ 763c609719bSwdenk } 764c609719bSwdenk 765c609719bSwdenk if (strlen(cmd) >= CFG_CBSIZE) { 766c609719bSwdenk puts ("## Command too long!\n"); 767c609719bSwdenk return -1; 768c609719bSwdenk } 769c609719bSwdenk 770c609719bSwdenk strcpy (cmdbuf, cmd); 771c609719bSwdenk 772c609719bSwdenk /* Process separators and check for invalid 773c609719bSwdenk * repeatable commands 774c609719bSwdenk */ 775c609719bSwdenk 776c609719bSwdenk #ifdef DEBUG_PARSER 777c609719bSwdenk printf ("[PROCESS_SEPARATORS] %s\n", cmd); 778c609719bSwdenk #endif 779c609719bSwdenk while (*str) { 780c609719bSwdenk 781c609719bSwdenk /* 782c609719bSwdenk * Find separator, or string end 783c609719bSwdenk * Allow simple escape of ';' by writing "\;" 784c609719bSwdenk */ 785a25f862bSwdenk for (inquotes = 0, sep = str; *sep; sep++) { 786a25f862bSwdenk if ((*sep=='\'') && 787a25f862bSwdenk (*(sep-1) != '\\')) 788a25f862bSwdenk inquotes=!inquotes; 789a25f862bSwdenk 790a25f862bSwdenk if (!inquotes && 791a25f862bSwdenk (*sep == ';') && /* separator */ 792c609719bSwdenk ( sep != str) && /* past string start */ 793c609719bSwdenk (*(sep-1) != '\\')) /* and NOT escaped */ 794c609719bSwdenk break; 795c609719bSwdenk } 796c609719bSwdenk 797c609719bSwdenk /* 798c609719bSwdenk * Limit the token to data between separators 799c609719bSwdenk */ 800c609719bSwdenk token = str; 801c609719bSwdenk if (*sep) { 802c609719bSwdenk str = sep + 1; /* start of command for next pass */ 803c609719bSwdenk *sep = '\0'; 804c609719bSwdenk } 805c609719bSwdenk else 806c609719bSwdenk str = sep; /* no more commands for next pass */ 807c609719bSwdenk #ifdef DEBUG_PARSER 808c609719bSwdenk printf ("token: \"%s\"\n", token); 809c609719bSwdenk #endif 810c609719bSwdenk 811c609719bSwdenk /* find macros in this token and replace them */ 812c609719bSwdenk process_macros (token, finaltoken); 813c609719bSwdenk 814c609719bSwdenk /* Extract arguments */ 815c609719bSwdenk argc = parse_line (finaltoken, argv); 816c609719bSwdenk 817c609719bSwdenk /* Look up command in command table */ 818c609719bSwdenk if ((cmdtp = find_cmd(argv[0])) == NULL) { 819c609719bSwdenk printf ("Unknown command '%s' - try 'help'\n", argv[0]); 820c609719bSwdenk return -1; /* give up after bad command */ 821c609719bSwdenk } 822c609719bSwdenk 823c609719bSwdenk /* found - check max args */ 824c609719bSwdenk if (argc > cmdtp->maxargs) { 825c609719bSwdenk printf ("Usage:\n%s\n", cmdtp->usage); 826c609719bSwdenk return -1; 827c609719bSwdenk } 828c609719bSwdenk 829c609719bSwdenk #if (CONFIG_COMMANDS & CFG_CMD_BOOTD) 830c609719bSwdenk /* avoid "bootd" recursion */ 831c609719bSwdenk if (cmdtp->cmd == do_bootd) { 832c609719bSwdenk #ifdef DEBUG_PARSER 833c609719bSwdenk printf ("[%s]\n", finaltoken); 834c609719bSwdenk #endif 835c609719bSwdenk if (flag & CMD_FLAG_BOOTD) { 836c609719bSwdenk printf ("'bootd' recursion detected\n"); 837c609719bSwdenk return -1; 838c609719bSwdenk } 839c609719bSwdenk else 840c609719bSwdenk flag |= CMD_FLAG_BOOTD; 841c609719bSwdenk } 842c609719bSwdenk #endif /* CFG_CMD_BOOTD */ 843c609719bSwdenk 844c609719bSwdenk /* OK - call function to do the command */ 845c609719bSwdenk if ((cmdtp->cmd) (cmdtp, flag, argc, argv) != 0) { 846c609719bSwdenk return (-1); 847c609719bSwdenk } 848c609719bSwdenk 849c609719bSwdenk repeatable &= cmdtp->repeatable; 850c609719bSwdenk 851c609719bSwdenk /* Did the user stop this? */ 852c609719bSwdenk if (had_ctrlc ()) 853c609719bSwdenk return 0; /* if stopped then not repeatable */ 854c609719bSwdenk } 855c609719bSwdenk 856c609719bSwdenk return repeatable; 857c609719bSwdenk } 858c609719bSwdenk 859c609719bSwdenk /****************************************************************************/ 860c609719bSwdenk 861c609719bSwdenk #if (CONFIG_COMMANDS & CFG_CMD_RUN) 862c609719bSwdenk int do_run (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) 863c609719bSwdenk { 864c609719bSwdenk int i; 865c609719bSwdenk 866c609719bSwdenk if (argc < 2) { 867c609719bSwdenk printf ("Usage:\n%s\n", cmdtp->usage); 868c609719bSwdenk return 1; 869c609719bSwdenk } 870c609719bSwdenk 871c609719bSwdenk for (i=1; i<argc; ++i) { 872*3e38691eSwdenk char *arg; 873*3e38691eSwdenk 874*3e38691eSwdenk if ((arg = getenv (argv[i])) == NULL) { 875*3e38691eSwdenk printf ("## Error: \"%s\" not defined\n", argv[i]); 876*3e38691eSwdenk return 1; 877*3e38691eSwdenk } 878c609719bSwdenk #ifndef CFG_HUSH_PARSER 879*3e38691eSwdenk if (run_command (arg, flag) == -1) 880*3e38691eSwdenk return 1; 881c609719bSwdenk #else 882*3e38691eSwdenk if (parse_string_outer(arg, 883*3e38691eSwdenk FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP) == 0) 884*3e38691eSwdenk return 1; 885c609719bSwdenk #endif 886c609719bSwdenk } 887*3e38691eSwdenk return 0; 888c609719bSwdenk } 889*3e38691eSwdenk #endif /* CFG_CMD_RUN */ 890