X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=common%2Fmain.c;h=44fa20dd6ac3648c674fa71b5749006d0bad961b;hb=2c601c7208713ba9b2158c57adcf515f4bdbc212;hp=f7e7c1c3269c4e8a356defac590a591e6762cbdd;hpb=83653121d7382fccfe329cb732f77f116341ef1d;p=platform%2Fkernel%2Fu-boot.git diff --git a/common/main.c b/common/main.c index f7e7c1c..44fa20d 100644 --- a/common/main.c +++ b/common/main.c @@ -30,6 +30,9 @@ #include #include #include +#include +#include +#include #ifdef CONFIG_MODEM_SUPPORT #include /* for free() prototype */ #endif @@ -38,11 +41,19 @@ #include #endif +#ifdef CONFIG_OF_CONTROL +#include +#endif + +#ifdef CONFIG_OF_LIBFDT +#include +#endif /* CONFIG_OF_LIBFDT */ + #include +#include +#include -#if defined(CONFIG_SILENT_CONSOLE) || defined(CONFIG_POST) || defined(CONFIG_CMDLINE_EDITING) DECLARE_GLOBAL_DATA_PTR; -#endif /* * Board-specific Platform code can reimplement show_boot_progress () if needed @@ -50,29 +61,19 @@ DECLARE_GLOBAL_DATA_PTR; void inline __show_boot_progress (int val) {} void show_boot_progress (int val) __attribute__((weak, alias("__show_boot_progress"))); -#if defined(CONFIG_BOOT_RETRY_TIME) && defined(CONFIG_RESET_TO_RETRY) -extern int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]); /* for do_reset() prototype */ -#endif - -extern int do_bootd (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]); - #if defined(CONFIG_UPDATE_TFTP) -void update_tftp (void); +int update_tftp (ulong addr); #endif /* CONFIG_UPDATE_TFTP */ #define MAX_DELAY_STOP_STR 32 -#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0) -static int abortboot(int); -#endif - #undef DEBUG_PARSER char console_buffer[CONFIG_SYS_CBSIZE + 1]; /* console I/O buffer */ static char * delete_char (char *buffer, char *p, int *colp, int *np, int plen); -static char erase_seq[] = "\b \b"; /* erase sequence */ -static char tab_seq[] = " "; /* used to expand TABs */ +static const char erase_seq[] = "\b \b"; /* erase sequence */ +static const char tab_seq[] = " "; /* used to expand TABs */ #ifdef CONFIG_BOOT_RETRY_TIME static uint64_t endtime = 0; /* must be set, default is instant timeout */ @@ -92,12 +93,14 @@ extern void mdm_init(void); /* defined in board.c */ /*************************************************************************** * Watch for 'delay' seconds for autoboot stop or autoboot delay string. - * returns: 0 - no key string, allow autoboot - * 1 - got key string, abort + * returns: 0 - no key string, allow autoboot 1 - got key string, abort */ #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0) # if defined(CONFIG_AUTOBOOT_KEYED) -static __inline__ int abortboot(int bootdelay) +#ifndef CONFIG_MENU +static inline +#endif +int abortboot(int bootdelay) { int abort = 0; uint64_t etime = endtick(bootdelay); @@ -118,6 +121,11 @@ static __inline__ int abortboot(int bootdelay) u_int presskey_max = 0; u_int i; +#ifndef CONFIG_ZERO_BOOTDELAY_CHECK + if (bootdelay == 0) + return 0; +#endif + # ifdef CONFIG_AUTOBOOT_PROMPT printf(CONFIG_AUTOBOOT_PROMPT); # endif @@ -211,14 +219,18 @@ static __inline__ int abortboot(int bootdelay) static int menukey = 0; #endif -static __inline__ int abortboot(int bootdelay) +#ifndef CONFIG_MENU +static inline +#endif +int abortboot(int bootdelay) { int abort = 0; #ifdef CONFIG_MENUPROMPT printf(CONFIG_MENUPROMPT); #else - printf("Hit any key to stop autoboot: %2d ", bootdelay); + if (bootdelay >= 0) + printf("Hit any key to stop autoboot: %2d ", bootdelay); #endif #if defined CONFIG_ZERO_BOOTDELAY_CHECK @@ -269,6 +281,73 @@ static __inline__ int abortboot(int bootdelay) # endif /* CONFIG_AUTOBOOT_KEYED */ #endif /* CONFIG_BOOTDELAY >= 0 */ +/* + * Runs the given boot command securely. Specifically: + * - Doesn't run the command with the shell (run_command or parse_string_outer), + * since that's a lot of code surface that an attacker might exploit. + * Because of this, we don't do any argument parsing--the secure boot command + * has to be a full-fledged u-boot command. + * - Doesn't check for keypresses before booting, since that could be a + * security hole; also disables Ctrl-C. + * - Doesn't allow the command to return. + * + * Upon any failures, this function will drop into an infinite loop after + * printing the error message to console. + */ + +#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0) && \ + defined(CONFIG_OF_CONTROL) +static void secure_boot_cmd(char *cmd) +{ + cmd_tbl_t *cmdtp; + int rc; + + if (!cmd) { + printf("## Error: Secure boot command not specified\n"); + goto err; + } + + /* Disable Ctrl-C just in case some command is used that checks it. */ + disable_ctrlc(1); + + /* Find the command directly. */ + cmdtp = find_cmd(cmd); + if (!cmdtp) { + printf("## Error: \"%s\" not defined\n", cmd); + goto err; + } + + /* Run the command, forcing no flags and faking argc and argv. */ + rc = (cmdtp->cmd)(cmdtp, 0, 1, &cmd); + + /* Shouldn't ever return from boot command. */ + printf("## Error: \"%s\" returned (code %d)\n", cmd, rc); + +err: + /* + * Not a whole lot to do here. Rebooting won't help much, since we'll + * just end up right back here. Just loop. + */ + hang(); +} + +static void process_fdt_options(const void *blob) +{ + ulong addr; + + /* Add an env variable to point to a kernel payload, if available */ + addr = fdtdec_get_config_int(gd->fdt_blob, "kernel-offset", 0); + if (addr) + setenv_addr("kernaddr", (void *)(CONFIG_SYS_TEXT_BASE + addr)); + + /* Add an env variable to point to a root disk, if available */ + addr = fdtdec_get_config_int(gd->fdt_blob, "rootdisk-offset", 0); + if (addr) + setenv_addr("rootaddr", (void *)(CONFIG_SYS_TEXT_BASE + addr)); +} +#endif /* CONFIG_OF_CONTROL */ + + /****************************************************************************/ void main_loop (void) @@ -279,7 +358,10 @@ void main_loop (void) int rc = 1; int flag; #endif - +#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0) && \ + defined(CONFIG_OF_CONTROL) + char *env; +#endif #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0) char *s; int bootdelay; @@ -294,17 +376,6 @@ void main_loop (void) char bcs_set[16]; #endif /* CONFIG_BOOTCOUNT_LIMIT */ -#if defined(CONFIG_VFD) && defined(VFD_TEST_LOGO) - ulong bmp = 0; /* default bitmap */ - extern int trab_vfd (ulong bitmap); - -#ifdef CONFIG_MODEM_SUPPORT - if (do_mdm_init) - bmp = 1; /* alternate bitmap */ -#endif - trab_vfd (bmp); -#endif /* CONFIG_VFD && VFD_TEST_LOGO */ - #ifdef CONFIG_BOOTCOUNT_LIMIT bootcount = bootcount_load(); bootcount++; @@ -328,8 +399,6 @@ void main_loop (void) #ifdef CONFIG_VERSION_VARIABLE { - extern char version_string[]; - setenv ("ver", version_string); /* set version variable */ } #endif /* CONFIG_VERSION_VARIABLE */ @@ -342,22 +411,13 @@ void main_loop (void) hush_init_var (); #endif -#ifdef CONFIG_AUTO_COMPLETE - install_auto_complete(); -#endif - #ifdef CONFIG_PREBOOT if ((p = getenv ("preboot")) != NULL) { # ifdef CONFIG_AUTOBOOT_KEYED int prev = disable_ctrlc(1); /* disable Control C checking */ # endif -# ifndef CONFIG_SYS_HUSH_PARSER - run_command (p, 0); -# else - parse_string_outer(p, FLAG_PARSE_SEMICOLON | - FLAG_EXIT_FROM_LOOP); -# endif + run_command_list(p, -1, 0); # ifdef CONFIG_AUTOBOOT_KEYED disable_ctrlc(prev); /* restore Control C checking */ @@ -366,7 +426,7 @@ void main_loop (void) #endif /* CONFIG_PREBOOT */ #if defined(CONFIG_UPDATE_TFTP) - update_tftp (); + update_tftp (0UL); #endif /* CONFIG_UPDATE_TFTP */ #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0) @@ -375,6 +435,9 @@ void main_loop (void) debug ("### main_loop entered: bootdelay=%d\n\n", bootdelay); +#if defined(CONFIG_MENU_SHOW) + bootdelay = menu_show(bootdelay); +#endif # ifdef CONFIG_BOOT_RETRY_TIME init_cmd_timeout (); # endif /* CONFIG_BOOT_RETRY_TIME */ @@ -394,20 +457,32 @@ void main_loop (void) else #endif /* CONFIG_BOOTCOUNT_LIMIT */ s = getenv ("bootcmd"); +#ifdef CONFIG_OF_CONTROL + /* Allow the fdt to override the boot command */ + env = fdtdec_get_config_string(gd->fdt_blob, "bootcmd"); + if (env) + s = env; + + process_fdt_options(gd->fdt_blob); + + /* + * If the bootsecure option was chosen, use secure_boot_cmd(). + * Always use 'env' in this case, since bootsecure requres that the + * bootcmd was specified in the FDT too. + */ + if (fdtdec_get_config_int(gd->fdt_blob, "bootsecure", 0)) + secure_boot_cmd(env); + +#endif /* CONFIG_OF_CONTROL */ debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : ""); - if (bootdelay >= 0 && s && !abortboot (bootdelay)) { + if (bootdelay != -1 && s && !abortboot(bootdelay)) { # ifdef CONFIG_AUTOBOOT_KEYED int prev = disable_ctrlc(1); /* disable Control C checking */ # endif -# ifndef CONFIG_SYS_HUSH_PARSER - run_command (s, 0); -# else - parse_string_outer(s, FLAG_PARSE_SEMICOLON | - FLAG_EXIT_FROM_LOOP); -# endif + run_command_list(s, -1, 0); # ifdef CONFIG_AUTOBOOT_KEYED disable_ctrlc(prev); /* restore Control C checking */ @@ -416,25 +491,16 @@ void main_loop (void) # ifdef CONFIG_MENUKEY if (menukey == CONFIG_MENUKEY) { - s = getenv("menucmd"); - if (s) { -# ifndef CONFIG_SYS_HUSH_PARSER - run_command (s, 0); -# else - parse_string_outer(s, FLAG_PARSE_SEMICOLON | - FLAG_EXIT_FROM_LOOP); -# endif - } + s = getenv("menucmd"); + if (s) + run_command_list(s, -1, 0); } #endif /* CONFIG_MENUKEY */ -#endif /* CONFIG_BOOTDELAY */ +#endif /* CONFIG_BOOTDELAY */ -#ifdef CONFIG_AMIGAONEG3SE - { - extern void video_banner(void); - video_banner(); - } -#endif +#if defined CONFIG_OF_CONTROL + set_working_fdt_addr((void *)gd->fdt_blob); +#endif /* CONFIG_OF_CONTROL */ /* * Main Loop for Monitor Command Processing @@ -477,7 +543,7 @@ void main_loop (void) if (len == -1) puts ("\n"); else - rc = run_command (lastcommand, flag); + rc = run_command(lastcommand, flag); if (rc <= 0) { /* invalid command or not repeatable, forget it */ @@ -525,9 +591,6 @@ void reset_cmd_timeout(void) } while (0) #define CTL_CH(c) ((c) - 'a' + 1) - -#define MAX_CMDBUF_SIZE CONFIG_SYS_CBSIZE - #define CTL_BACKSPACE ('\b') #define DEL ((char)255) #define DEL7 ((char)127) @@ -538,15 +601,15 @@ void reset_cmd_timeout(void) #define getcmd_cbeep() getcmd_putch('\a') #define HIST_MAX 20 -#define HIST_SIZE MAX_CMDBUF_SIZE +#define HIST_SIZE CONFIG_SYS_CBSIZE -static int hist_max = 0; -static int hist_add_idx = 0; +static int hist_max; +static int hist_add_idx; static int hist_cur = -1; -unsigned hist_num = 0; +static unsigned hist_num; -char* hist_list[HIST_MAX]; -char hist_lines[HIST_MAX][HIST_SIZE + 1]; /* Save room for NULL */ +static char *hist_list[HIST_MAX]; +static char hist_lines[HIST_MAX][HIST_SIZE + 1]; /* Save room for NULL */ #define add_idx_minus_one() ((hist_add_idx == 0) ? hist_max : hist_add_idx-1) @@ -650,12 +713,10 @@ static void cread_print_hist_list(void) #define ERASE_TO_EOL() { \ if (num < eol_num) { \ - int tmp; \ - for (tmp = num; tmp < eol_num; tmp++) \ - getcmd_putch(' '); \ - while (tmp-- > num) \ + printf("%*s", (int)(eol_num - num), ""); \ + do { \ getcmd_putch(CTL_BACKSPACE); \ - eol_num = num; \ + } while (--eol_num > num); \ } \ } @@ -711,7 +772,8 @@ static void cread_add_str(char *str, int strsize, int insert, unsigned long *num } } -static int cread_line(const char *const prompt, char *buf, unsigned int *len) +static int cread_line(const char *const prompt, char *buf, unsigned int *len, + int timeout) { unsigned long num = 0; unsigned long eol_num = 0; @@ -721,6 +783,7 @@ static int cread_line(const char *const prompt, char *buf, unsigned int *len) int esc_len = 0; char esc_save[8]; int init_len = strlen(buf); + int first = 1; if (init_len) cread_add_str(buf, init_len, 1, &num, &eol_num, buf, *len); @@ -733,6 +796,16 @@ static int cread_line(const char *const prompt, char *buf, unsigned int *len) WATCHDOG_RESET(); } #endif + if (first && timeout) { + uint64_t etime = endtick(timeout); + + while (!tstc()) { /* while no incoming data */ + if (get_ticks() >= etime) + return -2; /* timed out */ + WATCHDOG_RESET(); + } + first = 0; + } ichar = getcmd_getch(); @@ -948,15 +1021,15 @@ int readline (const char *const prompt) */ console_buffer[0] = '\0'; - return readline_into_buffer(prompt, console_buffer); + return readline_into_buffer(prompt, console_buffer, 0); } -int readline_into_buffer (const char *const prompt, char * buffer) +int readline_into_buffer(const char *const prompt, char *buffer, int timeout) { char *p = buffer; #ifdef CONFIG_CMDLINE_EDITING - unsigned int len=MAX_CMDBUF_SIZE; + unsigned int len = CONFIG_SYS_CBSIZE; int rc; static int initted = 0; @@ -975,7 +1048,7 @@ int readline_into_buffer (const char *const prompt, char * buffer) if (prompt) puts (prompt); - rc = cread_line(prompt, p, &len); + rc = cread_line(prompt, p, &len, timeout); return rc < 0 ? rc : len; } else { @@ -1005,7 +1078,6 @@ int readline_into_buffer (const char *const prompt, char * buffer) #ifdef CONFIG_SHOW_ACTIVITY while (!tstc()) { - extern void show_activity(int arg); show_activity(0); WATCHDOG_RESET(); } @@ -1067,8 +1139,16 @@ int readline_into_buffer (const char *const prompt, char * buffer) puts (tab_seq+(col&07)); col += 8 - (col&07); } else { - ++col; /* echo input */ - putc (c); + char buf[2]; + + /* + * Echo input using puts() to force am + * LCD flush if we are using an LCD + */ + ++col; + buf[0] = c; + buf[1] = '\0'; + puts(buf); } *p++ = c; ++n; @@ -1126,9 +1206,8 @@ int parse_line (char *line, char *argv[]) while (nargs < CONFIG_SYS_MAXARGS) { /* skip any white space */ - while ((*line == ' ') || (*line == '\t')) { + while (isblank(*line)) ++line; - } if (*line == '\0') { /* end of line, no more args */ argv[nargs] = NULL; @@ -1141,9 +1220,8 @@ int parse_line (char *line, char *argv[]) argv[nargs++] = line; /* begin of argument string */ /* find end of string */ - while (*line && (*line != ' ') && (*line != '\t')) { + while (*line && !isblank(*line)) ++line; - } if (*line == '\0') { /* end of line, no more args */ argv[nargs] = NULL; @@ -1166,6 +1244,7 @@ int parse_line (char *line, char *argv[]) /****************************************************************************/ +#ifndef CONFIG_SYS_HUSH_PARSER static void process_macros (const char *input, char *output) { char c, prev; @@ -1292,10 +1371,8 @@ static void process_macros (const char *input, char *output) * the environment data, which may change magicly when the command we run * creates or modifies environment variables (like "bootp" does). */ - -int run_command (const char *cmd, int flag) +static int builtin_run_command(const char *cmd, int flag) { - cmd_tbl_t *cmdtp; char cmdbuf[CONFIG_SYS_CBSIZE]; /* working copy of cmd */ char *token; /* start of token in cmdbuf */ char *sep; /* end of token (separator) in cmdbuf */ @@ -1373,62 +1450,135 @@ int run_command (const char *cmd, int flag) continue; } - /* Look up command in command table */ - if ((cmdtp = find_cmd(argv[0])) == NULL) { - printf ("Unknown command '%s' - try 'help'\n", argv[0]); - rc = -1; /* give up after bad command */ - continue; - } - - /* found - check max args */ - if (argc > cmdtp->maxargs) { - cmd_usage(cmdtp); + if (cmd_process(flag, argc, argv, &repeatable)) rc = -1; - continue; - } -#if defined(CONFIG_CMD_BOOTD) - /* avoid "bootd" recursion */ - if (cmdtp->cmd == do_bootd) { -#ifdef DEBUG_PARSER - printf ("[%s]\n", finaltoken); + /* Did the user stop this? */ + if (had_ctrlc ()) + return -1; /* if stopped then not repeatable */ + } + + return rc ? rc : repeatable; +} #endif - if (flag & CMD_FLAG_BOOTD) { - puts ("'bootd' recursion detected\n"); - rc = -1; - continue; - } else { - flag |= CMD_FLAG_BOOTD; - } - } + +/* + * Run a command using the selected parser. + * + * @param cmd Command to run + * @param flag Execution flags (CMD_FLAG_...) + * @return 0 on success, or != 0 on error. + */ +int run_command(const char *cmd, int flag) +{ +#ifndef CONFIG_SYS_HUSH_PARSER + /* + * builtin_run_command can return 0 or 1 for success, so clean up + * its result. + */ + if (builtin_run_command(cmd, flag) == -1) + return 1; + + return 0; +#else + return parse_string_outer(cmd, + FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP); #endif +} - /* OK - call function to do the command */ - if ((cmdtp->cmd) (cmdtp, flag, argc, argv) != 0) { - rc = -1; +#ifndef CONFIG_SYS_HUSH_PARSER +/** + * Execute a list of command separated by ; or \n using the built-in parser. + * + * This function cannot take a const char * for the command, since if it + * finds newlines in the string, it replaces them with \0. + * + * @param cmd String containing list of commands + * @param flag Execution flags (CMD_FLAG_...) + * @return 0 on success, or != 0 on error. + */ +static int builtin_run_command_list(char *cmd, int flag) +{ + char *line, *next; + int rcode = 0; + + /* + * Break into individual lines, and execute each line; terminate on + * error. + */ + line = next = cmd; + while (*next) { + if (*next == '\n') { + *next = '\0'; + /* run only non-empty commands */ + if (*line) { + debug("** exec: \"%s\"\n", line); + if (builtin_run_command(line, 0) < 0) { + rcode = 1; + break; + } + } + line = next + 1; } + ++next; + } + if (rcode == 0 && *line) + rcode = (builtin_run_command(line, 0) >= 0); - repeatable &= cmdtp->repeatable; + return rcode; +} +#endif - /* Did the user stop this? */ - if (had_ctrlc ()) - return -1; /* if stopped then not repeatable */ +int run_command_list(const char *cmd, int len, int flag) +{ + int need_buff = 1; + char *buff = (char *)cmd; /* cast away const */ + int rcode = 0; + + if (len == -1) { + len = strlen(cmd); +#ifdef CONFIG_SYS_HUSH_PARSER + /* hush will never change our string */ + need_buff = 0; +#else + /* the built-in parser will change our string if it sees \n */ + need_buff = strchr(cmd, '\n') != NULL; +#endif } + if (need_buff) { + buff = malloc(len + 1); + if (!buff) + return 1; + memcpy(buff, cmd, len); + buff[len] = '\0'; + } +#ifdef CONFIG_SYS_HUSH_PARSER + rcode = parse_string_outer(buff, FLAG_PARSE_SEMICOLON); +#else + /* + * This function will overwrite any \n it sees with a \0, which + * is why it can't work with a const char *. Here we are making + * using of internal knowledge of this function, to avoid always + * doing a malloc() which is actually required only in a case that + * is pretty rare. + */ + rcode = builtin_run_command_list(buff, flag); + if (need_buff) + free(buff); +#endif - return rc ? rc : repeatable; + return rcode; } /****************************************************************************/ #if defined(CONFIG_CMD_RUN) -int do_run (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) +int do_run (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) { int i; - if (argc < 2) { - cmd_usage(cmdtp); - return 1; - } + if (argc < 2) + return CMD_RET_USAGE; for (i=1; i