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