]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - common/main.c
Split out simple parser and readline into separate files
[karo-tx-uboot.git] / common / main.c
1 /*
2  * (C) Copyright 2000
3  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4  *
5  * SPDX-License-Identifier:     GPL-2.0+
6  */
7
8 /* #define      DEBUG   */
9
10 #include <common.h>
11 #include <cli.h>
12 #include <command.h>
13 #include <fdtdec.h>
14 #include <cli_hush.h>
15 #include <malloc.h>
16 #include <menu.h>
17 #include <post.h>
18 #include <version.h>
19
20 DECLARE_GLOBAL_DATA_PTR;
21
22 /*
23  * Board-specific Platform code can reimplement show_boot_progress () if needed
24  */
25 void inline __show_boot_progress (int val) {}
26 void show_boot_progress (int val) __attribute__((weak, alias("__show_boot_progress")));
27
28 #define MAX_DELAY_STOP_STR 32
29
30 #ifndef DEBUG_BOOTKEYS
31 #define DEBUG_BOOTKEYS 0
32 #endif
33 #define debug_bootkeys(fmt, args...)            \
34         debug_cond(DEBUG_BOOTKEYS, fmt, ##args)
35
36 #ifdef CONFIG_MODEM_SUPPORT
37 int do_mdm_init = 0;
38 extern void mdm_init(void); /* defined in board.c */
39 #endif
40
41 /***************************************************************************
42  * Watch for 'delay' seconds for autoboot stop or autoboot delay string.
43  * returns: 0 -  no key string, allow autoboot 1 - got key string, abort
44  */
45 #if defined(CONFIG_BOOTDELAY)
46 # if defined(CONFIG_AUTOBOOT_KEYED)
47 static int abortboot_keyed(int bootdelay)
48 {
49         int abort = 0;
50         uint64_t etime = endtick(bootdelay);
51         struct {
52                 char* str;
53                 u_int len;
54                 int retry;
55         }
56         delaykey [] = {
57                 { str: getenv ("bootdelaykey"),  retry: 1 },
58                 { str: getenv ("bootdelaykey2"), retry: 1 },
59                 { str: getenv ("bootstopkey"),   retry: 0 },
60                 { str: getenv ("bootstopkey2"),  retry: 0 },
61         };
62
63         char presskey [MAX_DELAY_STOP_STR];
64         u_int presskey_len = 0;
65         u_int presskey_max = 0;
66         u_int i;
67
68 #ifndef CONFIG_ZERO_BOOTDELAY_CHECK
69         if (bootdelay == 0)
70                 return 0;
71 #endif
72
73 #  ifdef CONFIG_AUTOBOOT_PROMPT
74         printf(CONFIG_AUTOBOOT_PROMPT);
75 #  endif
76
77 #  ifdef CONFIG_AUTOBOOT_DELAY_STR
78         if (delaykey[0].str == NULL)
79                 delaykey[0].str = CONFIG_AUTOBOOT_DELAY_STR;
80 #  endif
81 #  ifdef CONFIG_AUTOBOOT_DELAY_STR2
82         if (delaykey[1].str == NULL)
83                 delaykey[1].str = CONFIG_AUTOBOOT_DELAY_STR2;
84 #  endif
85 #  ifdef CONFIG_AUTOBOOT_STOP_STR
86         if (delaykey[2].str == NULL)
87                 delaykey[2].str = CONFIG_AUTOBOOT_STOP_STR;
88 #  endif
89 #  ifdef CONFIG_AUTOBOOT_STOP_STR2
90         if (delaykey[3].str == NULL)
91                 delaykey[3].str = CONFIG_AUTOBOOT_STOP_STR2;
92 #  endif
93
94         for (i = 0; i < sizeof(delaykey) / sizeof(delaykey[0]); i ++) {
95                 delaykey[i].len = delaykey[i].str == NULL ?
96                                     0 : strlen (delaykey[i].str);
97                 delaykey[i].len = delaykey[i].len > MAX_DELAY_STOP_STR ?
98                                     MAX_DELAY_STOP_STR : delaykey[i].len;
99
100                 presskey_max = presskey_max > delaykey[i].len ?
101                                     presskey_max : delaykey[i].len;
102
103                 debug_bootkeys("%s key:<%s>\n",
104                                delaykey[i].retry ? "delay" : "stop",
105                                delaykey[i].str ? delaykey[i].str : "NULL");
106         }
107
108         /* In order to keep up with incoming data, check timeout only
109          * when catch up.
110          */
111         do {
112                 if (tstc()) {
113                         if (presskey_len < presskey_max) {
114                                 presskey [presskey_len ++] = getc();
115                         }
116                         else {
117                                 for (i = 0; i < presskey_max - 1; i ++)
118                                         presskey [i] = presskey [i + 1];
119
120                                 presskey [i] = getc();
121                         }
122                 }
123
124                 for (i = 0; i < sizeof(delaykey) / sizeof(delaykey[0]); i ++) {
125                         if (delaykey[i].len > 0 &&
126                             presskey_len >= delaykey[i].len &&
127                             memcmp (presskey + presskey_len - delaykey[i].len,
128                                     delaykey[i].str,
129                                     delaykey[i].len) == 0) {
130                                 debug_bootkeys("got %skey\n",
131                                                delaykey[i].retry ? "delay" :
132                                                "stop");
133
134 #  ifdef CONFIG_BOOT_RETRY_TIME
135                                 /* don't retry auto boot */
136                                 if (! delaykey[i].retry)
137                                         bootretry_dont_retry();
138 #  endif
139                                 abort = 1;
140                         }
141                 }
142         } while (!abort && get_ticks() <= etime);
143
144         if (!abort)
145                 debug_bootkeys("key timeout\n");
146
147 #ifdef CONFIG_SILENT_CONSOLE
148         if (abort)
149                 gd->flags &= ~GD_FLG_SILENT;
150 #endif
151
152         return abort;
153 }
154
155 # else  /* !defined(CONFIG_AUTOBOOT_KEYED) */
156
157 #ifdef CONFIG_MENUKEY
158 static int menukey = 0;
159 #endif
160
161 static int abortboot_normal(int bootdelay)
162 {
163         int abort = 0;
164         unsigned long ts;
165
166 #ifdef CONFIG_MENUPROMPT
167         printf(CONFIG_MENUPROMPT);
168 #else
169         if (bootdelay >= 0)
170                 printf("Hit any key to stop autoboot: %2d ", bootdelay);
171 #endif
172
173 #if defined CONFIG_ZERO_BOOTDELAY_CHECK
174         /*
175          * Check if key already pressed
176          * Don't check if bootdelay < 0
177          */
178         if (bootdelay >= 0) {
179                 if (tstc()) {   /* we got a key press   */
180                         (void) getc();  /* consume input        */
181                         puts ("\b\b\b 0");
182                         abort = 1;      /* don't auto boot      */
183                 }
184         }
185 #endif
186
187         while ((bootdelay > 0) && (!abort)) {
188                 --bootdelay;
189                 /* delay 1000 ms */
190                 ts = get_timer(0);
191                 do {
192                         if (tstc()) {   /* we got a key press   */
193                                 abort  = 1;     /* don't auto boot      */
194                                 bootdelay = 0;  /* no more delay        */
195 # ifdef CONFIG_MENUKEY
196                                 menukey = getc();
197 # else
198                                 (void) getc();  /* consume input        */
199 # endif
200                                 break;
201                         }
202                         udelay(10000);
203                 } while (!abort && get_timer(ts) < 1000);
204
205                 printf("\b\b\b%2d ", bootdelay);
206         }
207
208         putc('\n');
209
210 #ifdef CONFIG_SILENT_CONSOLE
211         if (abort)
212                 gd->flags &= ~GD_FLG_SILENT;
213 #endif
214
215         return abort;
216 }
217 # endif /* CONFIG_AUTOBOOT_KEYED */
218
219 static int abortboot(int bootdelay)
220 {
221 #ifdef CONFIG_AUTOBOOT_KEYED
222         return abortboot_keyed(bootdelay);
223 #else
224         return abortboot_normal(bootdelay);
225 #endif
226 }
227 #endif  /* CONFIG_BOOTDELAY */
228
229 /*
230  * Runs the given boot command securely.  Specifically:
231  * - Doesn't run the command with the shell (run_command or parse_string_outer),
232  *   since that's a lot of code surface that an attacker might exploit.
233  *   Because of this, we don't do any argument parsing--the secure boot command
234  *   has to be a full-fledged u-boot command.
235  * - Doesn't check for keypresses before booting, since that could be a
236  *   security hole; also disables Ctrl-C.
237  * - Doesn't allow the command to return.
238  *
239  * Upon any failures, this function will drop into an infinite loop after
240  * printing the error message to console.
241  */
242
243 #if defined(CONFIG_BOOTDELAY) && defined(CONFIG_OF_CONTROL)
244 static void secure_boot_cmd(char *cmd)
245 {
246         cmd_tbl_t *cmdtp;
247         int rc;
248
249         if (!cmd) {
250                 printf("## Error: Secure boot command not specified\n");
251                 goto err;
252         }
253
254         /* Disable Ctrl-C just in case some command is used that checks it. */
255         disable_ctrlc(1);
256
257         /* Find the command directly. */
258         cmdtp = find_cmd(cmd);
259         if (!cmdtp) {
260                 printf("## Error: \"%s\" not defined\n", cmd);
261                 goto err;
262         }
263
264         /* Run the command, forcing no flags and faking argc and argv. */
265         rc = (cmdtp->cmd)(cmdtp, 0, 1, &cmd);
266
267         /* Shouldn't ever return from boot command. */
268         printf("## Error: \"%s\" returned (code %d)\n", cmd, rc);
269
270 err:
271         /*
272          * Not a whole lot to do here.  Rebooting won't help much, since we'll
273          * just end up right back here.  Just loop.
274          */
275         hang();
276 }
277
278 static void process_fdt_options(const void *blob)
279 {
280         ulong addr;
281
282         /* Add an env variable to point to a kernel payload, if available */
283         addr = fdtdec_get_config_int(gd->fdt_blob, "kernel-offset", 0);
284         if (addr)
285                 setenv_addr("kernaddr", (void *)(CONFIG_SYS_TEXT_BASE + addr));
286
287         /* Add an env variable to point to a root disk, if available */
288         addr = fdtdec_get_config_int(gd->fdt_blob, "rootdisk-offset", 0);
289         if (addr)
290                 setenv_addr("rootaddr", (void *)(CONFIG_SYS_TEXT_BASE + addr));
291 }
292 #endif /* CONFIG_OF_CONTROL */
293
294 #ifdef CONFIG_BOOTDELAY
295 static void process_boot_delay(void)
296 {
297 #ifdef CONFIG_OF_CONTROL
298         char *env;
299 #endif
300         char *s;
301         int bootdelay;
302 #ifdef CONFIG_BOOTCOUNT_LIMIT
303         unsigned long bootcount = 0;
304         unsigned long bootlimit = 0;
305 #endif /* CONFIG_BOOTCOUNT_LIMIT */
306
307 #ifdef CONFIG_BOOTCOUNT_LIMIT
308         bootcount = bootcount_load();
309         bootcount++;
310         bootcount_store (bootcount);
311         setenv_ulong("bootcount", bootcount);
312         bootlimit = getenv_ulong("bootlimit", 10, 0);
313 #endif /* CONFIG_BOOTCOUNT_LIMIT */
314
315         s = getenv ("bootdelay");
316         bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;
317
318 #ifdef CONFIG_OF_CONTROL
319         bootdelay = fdtdec_get_config_int(gd->fdt_blob, "bootdelay",
320                         bootdelay);
321 #endif
322
323         debug ("### main_loop entered: bootdelay=%d\n\n", bootdelay);
324
325 #if defined(CONFIG_MENU_SHOW)
326         bootdelay = menu_show(bootdelay);
327 #endif
328 # ifdef CONFIG_BOOT_RETRY_TIME
329         init_cmd_timeout ();
330 # endif /* CONFIG_BOOT_RETRY_TIME */
331
332 #ifdef CONFIG_POST
333         if (gd->flags & GD_FLG_POSTFAIL) {
334                 s = getenv("failbootcmd");
335         }
336         else
337 #endif /* CONFIG_POST */
338 #ifdef CONFIG_BOOTCOUNT_LIMIT
339         if (bootlimit && (bootcount > bootlimit)) {
340                 printf ("Warning: Bootlimit (%u) exceeded. Using altbootcmd.\n",
341                         (unsigned)bootlimit);
342                 s = getenv ("altbootcmd");
343         }
344         else
345 #endif /* CONFIG_BOOTCOUNT_LIMIT */
346                 s = getenv ("bootcmd");
347 #ifdef CONFIG_OF_CONTROL
348         /* Allow the fdt to override the boot command */
349         env = fdtdec_get_config_string(gd->fdt_blob, "bootcmd");
350         if (env)
351                 s = env;
352
353         process_fdt_options(gd->fdt_blob);
354
355         /*
356          * If the bootsecure option was chosen, use secure_boot_cmd().
357          * Always use 'env' in this case, since bootsecure requres that the
358          * bootcmd was specified in the FDT too.
359          */
360         if (fdtdec_get_config_int(gd->fdt_blob, "bootsecure", 0))
361                 secure_boot_cmd(env);
362
363 #endif /* CONFIG_OF_CONTROL */
364
365         debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>");
366
367         if (bootdelay != -1 && s && !abortboot(bootdelay)) {
368 #if defined(CONFIG_AUTOBOOT_KEYED) && !defined(CONFIG_AUTOBOOT_KEYED_CTRLC)
369                 int prev = disable_ctrlc(1);    /* disable Control C checking */
370 #endif
371
372                 run_command_list(s, -1, 0);
373
374 #if defined(CONFIG_AUTOBOOT_KEYED) && !defined(CONFIG_AUTOBOOT_KEYED_CTRLC)
375                 disable_ctrlc(prev);    /* restore Control C checking */
376 #endif
377         }
378
379 #ifdef CONFIG_MENUKEY
380         if (menukey == CONFIG_MENUKEY) {
381                 s = getenv("menucmd");
382                 if (s)
383                         run_command_list(s, -1, 0);
384         }
385 #endif /* CONFIG_MENUKEY */
386 }
387 #endif /* CONFIG_BOOTDELAY */
388
389 void main_loop(void)
390 {
391 #ifdef CONFIG_PREBOOT
392         char *p;
393 #endif
394
395         bootstage_mark_name(BOOTSTAGE_ID_MAIN_LOOP, "main_loop");
396
397 #ifndef CONFIG_SYS_GENERIC_BOARD
398         puts("Warning: Your board does not use generic board. Please read\n");
399         puts("doc/README.generic-board and take action. Boards not\n");
400         puts("upgraded by the late 2014 may break or be removed.\n");
401 #endif
402
403 #ifdef CONFIG_MODEM_SUPPORT
404         debug("DEBUG: main_loop:   do_mdm_init=%d\n", do_mdm_init);
405         if (do_mdm_init) {
406                 char *str = strdup(getenv("mdm_cmd"));
407                 setenv("preboot", str);  /* set or delete definition */
408                 if (str != NULL)
409                         free(str);
410                 mdm_init(); /* wait for modem connection */
411         }
412 #endif  /* CONFIG_MODEM_SUPPORT */
413
414 #ifdef CONFIG_VERSION_VARIABLE
415         {
416                 setenv("ver", version_string);  /* set version variable */
417         }
418 #endif /* CONFIG_VERSION_VARIABLE */
419
420 #ifdef CONFIG_SYS_HUSH_PARSER
421         u_boot_hush_start();
422 #endif
423
424 #if defined(CONFIG_HUSH_INIT_VAR)
425         hush_init_var();
426 #endif
427
428 #ifdef CONFIG_PREBOOT
429         p = getenv("preboot");
430         if (p != NULL) {
431 # ifdef CONFIG_AUTOBOOT_KEYED
432                 int prev = disable_ctrlc(1);    /* disable Control C checking */
433 # endif
434
435                 run_command_list(p, -1, 0);
436
437 # ifdef CONFIG_AUTOBOOT_KEYED
438                 disable_ctrlc(prev);    /* restore Control C checking */
439 # endif
440         }
441 #endif /* CONFIG_PREBOOT */
442
443 #if defined(CONFIG_UPDATE_TFTP)
444         update_tftp(0UL);
445 #endif /* CONFIG_UPDATE_TFTP */
446
447 #ifdef CONFIG_BOOTDELAY
448         process_boot_delay();
449 #endif
450         /*
451          * Main Loop for Monitor Command Processing
452          */
453 #ifdef CONFIG_SYS_HUSH_PARSER
454         parse_file_outer();
455         /* This point is never reached */
456         for (;;);
457 #else
458         cli_loop();
459 #endif /*CONFIG_SYS_HUSH_PARSER*/
460 }
461
462 /****************************************************************************/
463
464 /*
465  * Run a command using the selected parser.
466  *
467  * @param cmd   Command to run
468  * @param flag  Execution flags (CMD_FLAG_...)
469  * @return 0 on success, or != 0 on error.
470  */
471 int run_command(const char *cmd, int flag)
472 {
473 #ifndef CONFIG_SYS_HUSH_PARSER
474         /*
475          * cli_run_command can return 0 or 1 for success, so clean up
476          * its result.
477          */
478         if (cli_simple_run_command(cmd, flag) == -1)
479                 return 1;
480
481         return 0;
482 #else
483         return parse_string_outer(cmd,
484                         FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP);
485 #endif
486 }
487
488 int run_command_list(const char *cmd, int len, int flag)
489 {
490         int need_buff = 1;
491         char *buff = (char *)cmd;       /* cast away const */
492         int rcode = 0;
493
494         if (len == -1) {
495                 len = strlen(cmd);
496 #ifdef CONFIG_SYS_HUSH_PARSER
497                 /* hush will never change our string */
498                 need_buff = 0;
499 #else
500                 /* the built-in parser will change our string if it sees \n */
501                 need_buff = strchr(cmd, '\n') != NULL;
502 #endif
503         }
504         if (need_buff) {
505                 buff = malloc(len + 1);
506                 if (!buff)
507                         return 1;
508                 memcpy(buff, cmd, len);
509                 buff[len] = '\0';
510         }
511 #ifdef CONFIG_SYS_HUSH_PARSER
512         rcode = parse_string_outer(buff, FLAG_PARSE_SEMICOLON);
513 #else
514         /*
515          * This function will overwrite any \n it sees with a \0, which
516          * is why it can't work with a const char *. Here we are making
517          * using of internal knowledge of this function, to avoid always
518          * doing a malloc() which is actually required only in a case that
519          * is pretty rare.
520          */
521         rcode = cli_simple_run_command_list(buff, flag);
522         if (need_buff)
523                 free(buff);
524 #endif
525
526         return rcode;
527 }
528
529 /****************************************************************************/
530
531 #if defined(CONFIG_CMD_RUN)
532 int do_run (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
533 {
534         int i;
535
536         if (argc < 2)
537                 return CMD_RET_USAGE;
538
539         for (i=1; i<argc; ++i) {
540                 char *arg;
541
542                 if ((arg = getenv (argv[i])) == NULL) {
543                         printf ("## Error: \"%s\" not defined\n", argv[i]);
544                         return 1;
545                 }
546
547                 if (run_command_list(arg, -1, flag) != 0)
548                         return 1;
549         }
550         return 0;
551 }
552 #endif