autoboot.c 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. /*
  2. * (C) Copyright 2000
  3. * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
  4. *
  5. * SPDX-License-Identifier: GPL-2.0+
  6. */
  7. #include <common.h>
  8. #include <cli.h>
  9. #include <fdtdec.h>
  10. #include <menu.h>
  11. #include <post.h>
  12. DECLARE_GLOBAL_DATA_PTR;
  13. #define MAX_DELAY_STOP_STR 32
  14. #ifndef DEBUG_BOOTKEYS
  15. #define DEBUG_BOOTKEYS 0
  16. #endif
  17. #define debug_bootkeys(fmt, args...) \
  18. debug_cond(DEBUG_BOOTKEYS, fmt, ##args)
  19. /***************************************************************************
  20. * Watch for 'delay' seconds for autoboot stop or autoboot delay string.
  21. * returns: 0 - no key string, allow autoboot 1 - got key string, abort
  22. */
  23. # if defined(CONFIG_AUTOBOOT_KEYED)
  24. static int abortboot_keyed(int bootdelay)
  25. {
  26. int abort = 0;
  27. uint64_t etime = endtick(bootdelay);
  28. struct {
  29. char *str;
  30. u_int len;
  31. int retry;
  32. }
  33. delaykey[] = {
  34. { str: getenv("bootdelaykey"), retry: 1 },
  35. { str: getenv("bootdelaykey2"), retry: 1 },
  36. { str: getenv("bootstopkey"), retry: 0 },
  37. { str: getenv("bootstopkey2"), retry: 0 },
  38. };
  39. char presskey[MAX_DELAY_STOP_STR];
  40. u_int presskey_len = 0;
  41. u_int presskey_max = 0;
  42. u_int i;
  43. #ifndef CONFIG_ZERO_BOOTDELAY_CHECK
  44. if (bootdelay == 0)
  45. return 0;
  46. #endif
  47. # ifdef CONFIG_AUTOBOOT_PROMPT
  48. printf(CONFIG_AUTOBOOT_PROMPT);
  49. # endif
  50. # ifdef CONFIG_AUTOBOOT_DELAY_STR
  51. if (delaykey[0].str == NULL)
  52. delaykey[0].str = CONFIG_AUTOBOOT_DELAY_STR;
  53. # endif
  54. # ifdef CONFIG_AUTOBOOT_DELAY_STR2
  55. if (delaykey[1].str == NULL)
  56. delaykey[1].str = CONFIG_AUTOBOOT_DELAY_STR2;
  57. # endif
  58. # ifdef CONFIG_AUTOBOOT_STOP_STR
  59. if (delaykey[2].str == NULL)
  60. delaykey[2].str = CONFIG_AUTOBOOT_STOP_STR;
  61. # endif
  62. # ifdef CONFIG_AUTOBOOT_STOP_STR2
  63. if (delaykey[3].str == NULL)
  64. delaykey[3].str = CONFIG_AUTOBOOT_STOP_STR2;
  65. # endif
  66. for (i = 0; i < sizeof(delaykey) / sizeof(delaykey[0]); i++) {
  67. delaykey[i].len = delaykey[i].str == NULL ?
  68. 0 : strlen(delaykey[i].str);
  69. delaykey[i].len = delaykey[i].len > MAX_DELAY_STOP_STR ?
  70. MAX_DELAY_STOP_STR : delaykey[i].len;
  71. presskey_max = presskey_max > delaykey[i].len ?
  72. presskey_max : delaykey[i].len;
  73. debug_bootkeys("%s key:<%s>\n",
  74. delaykey[i].retry ? "delay" : "stop",
  75. delaykey[i].str ? delaykey[i].str : "NULL");
  76. }
  77. /* In order to keep up with incoming data, check timeout only
  78. * when catch up.
  79. */
  80. do {
  81. if (tstc()) {
  82. if (presskey_len < presskey_max) {
  83. presskey[presskey_len++] = getc();
  84. } else {
  85. for (i = 0; i < presskey_max - 1; i++)
  86. presskey[i] = presskey[i + 1];
  87. presskey[i] = getc();
  88. }
  89. }
  90. for (i = 0; i < sizeof(delaykey) / sizeof(delaykey[0]); i++) {
  91. if (delaykey[i].len > 0 &&
  92. presskey_len >= delaykey[i].len &&
  93. memcmp(presskey + presskey_len -
  94. delaykey[i].len, delaykey[i].str,
  95. delaykey[i].len) == 0) {
  96. debug_bootkeys("got %skey\n",
  97. delaykey[i].retry ? "delay" :
  98. "stop");
  99. # ifdef CONFIG_BOOT_RETRY_TIME
  100. /* don't retry auto boot */
  101. if (!delaykey[i].retry)
  102. bootretry_dont_retry();
  103. # endif
  104. abort = 1;
  105. }
  106. }
  107. } while (!abort && get_ticks() <= etime);
  108. if (!abort)
  109. debug_bootkeys("key timeout\n");
  110. #ifdef CONFIG_SILENT_CONSOLE
  111. if (abort)
  112. gd->flags &= ~GD_FLG_SILENT;
  113. #endif
  114. return abort;
  115. }
  116. # else /* !defined(CONFIG_AUTOBOOT_KEYED) */
  117. #ifdef CONFIG_MENUKEY
  118. static int menukey;
  119. #endif
  120. static int abortboot_normal(int bootdelay)
  121. {
  122. int abort = 0;
  123. unsigned long ts;
  124. #ifdef CONFIG_MENUPROMPT
  125. printf(CONFIG_MENUPROMPT);
  126. #else
  127. if (bootdelay >= 0)
  128. printf("Hit any key to stop autoboot: %2d ", bootdelay);
  129. #endif
  130. #if defined CONFIG_ZERO_BOOTDELAY_CHECK
  131. /*
  132. * Check if key already pressed
  133. * Don't check if bootdelay < 0
  134. */
  135. if (bootdelay >= 0) {
  136. if (tstc()) { /* we got a key press */
  137. (void) getc(); /* consume input */
  138. puts("\b\b\b 0");
  139. abort = 1; /* don't auto boot */
  140. }
  141. }
  142. #endif
  143. while ((bootdelay > 0) && (!abort)) {
  144. --bootdelay;
  145. /* delay 1000 ms */
  146. ts = get_timer(0);
  147. do {
  148. if (tstc()) { /* we got a key press */
  149. abort = 1; /* don't auto boot */
  150. bootdelay = 0; /* no more delay */
  151. # ifdef CONFIG_MENUKEY
  152. menukey = getc();
  153. # else
  154. (void) getc(); /* consume input */
  155. # endif
  156. break;
  157. }
  158. udelay(10000);
  159. } while (!abort && get_timer(ts) < 1000);
  160. printf("\b\b\b%2d ", bootdelay);
  161. }
  162. putc('\n');
  163. #ifdef CONFIG_SILENT_CONSOLE
  164. if (abort)
  165. gd->flags &= ~GD_FLG_SILENT;
  166. #endif
  167. return abort;
  168. }
  169. # endif /* CONFIG_AUTOBOOT_KEYED */
  170. static int abortboot(int bootdelay)
  171. {
  172. #ifdef CONFIG_AUTOBOOT_KEYED
  173. return abortboot_keyed(bootdelay);
  174. #else
  175. return abortboot_normal(bootdelay);
  176. #endif
  177. }
  178. /*
  179. * Runs the given boot command securely. Specifically:
  180. * - Doesn't run the command with the shell (run_command or parse_string_outer),
  181. * since that's a lot of code surface that an attacker might exploit.
  182. * Because of this, we don't do any argument parsing--the secure boot command
  183. * has to be a full-fledged u-boot command.
  184. * - Doesn't check for keypresses before booting, since that could be a
  185. * security hole; also disables Ctrl-C.
  186. * - Doesn't allow the command to return.
  187. *
  188. * Upon any failures, this function will drop into an infinite loop after
  189. * printing the error message to console.
  190. */
  191. #if defined(CONFIG_OF_CONTROL)
  192. static void secure_boot_cmd(char *cmd)
  193. {
  194. cmd_tbl_t *cmdtp;
  195. int rc;
  196. if (!cmd) {
  197. printf("## Error: Secure boot command not specified\n");
  198. goto err;
  199. }
  200. /* Disable Ctrl-C just in case some command is used that checks it. */
  201. disable_ctrlc(1);
  202. /* Find the command directly. */
  203. cmdtp = find_cmd(cmd);
  204. if (!cmdtp) {
  205. printf("## Error: \"%s\" not defined\n", cmd);
  206. goto err;
  207. }
  208. /* Run the command, forcing no flags and faking argc and argv. */
  209. rc = (cmdtp->cmd)(cmdtp, 0, 1, &cmd);
  210. /* Shouldn't ever return from boot command. */
  211. printf("## Error: \"%s\" returned (code %d)\n", cmd, rc);
  212. err:
  213. /*
  214. * Not a whole lot to do here. Rebooting won't help much, since we'll
  215. * just end up right back here. Just loop.
  216. */
  217. hang();
  218. }
  219. static void process_fdt_options(const void *blob)
  220. {
  221. ulong addr;
  222. /* Add an env variable to point to a kernel payload, if available */
  223. addr = fdtdec_get_config_int(gd->fdt_blob, "kernel-offset", 0);
  224. if (addr)
  225. setenv_addr("kernaddr", (void *)(CONFIG_SYS_TEXT_BASE + addr));
  226. /* Add an env variable to point to a root disk, if available */
  227. addr = fdtdec_get_config_int(gd->fdt_blob, "rootdisk-offset", 0);
  228. if (addr)
  229. setenv_addr("rootaddr", (void *)(CONFIG_SYS_TEXT_BASE + addr));
  230. }
  231. #endif /* CONFIG_OF_CONTROL */
  232. void bootdelay_process(void)
  233. {
  234. #ifdef CONFIG_OF_CONTROL
  235. char *env;
  236. #endif
  237. char *s;
  238. int bootdelay;
  239. #ifdef CONFIG_BOOTCOUNT_LIMIT
  240. unsigned long bootcount = 0;
  241. unsigned long bootlimit = 0;
  242. #endif /* CONFIG_BOOTCOUNT_LIMIT */
  243. #ifdef CONFIG_BOOTCOUNT_LIMIT
  244. bootcount = bootcount_load();
  245. bootcount++;
  246. bootcount_store(bootcount);
  247. setenv_ulong("bootcount", bootcount);
  248. bootlimit = getenv_ulong("bootlimit", 10, 0);
  249. #endif /* CONFIG_BOOTCOUNT_LIMIT */
  250. s = getenv("bootdelay");
  251. bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;
  252. #ifdef CONFIG_OF_CONTROL
  253. bootdelay = fdtdec_get_config_int(gd->fdt_blob, "bootdelay",
  254. bootdelay);
  255. #endif
  256. debug("### main_loop entered: bootdelay=%d\n\n", bootdelay);
  257. #if defined(CONFIG_MENU_SHOW)
  258. bootdelay = menu_show(bootdelay);
  259. #endif
  260. # ifdef CONFIG_BOOT_RETRY_TIME
  261. init_cmd_timeout();
  262. # endif /* CONFIG_BOOT_RETRY_TIME */
  263. #ifdef CONFIG_POST
  264. if (gd->flags & GD_FLG_POSTFAIL) {
  265. s = getenv("failbootcmd");
  266. } else
  267. #endif /* CONFIG_POST */
  268. #ifdef CONFIG_BOOTCOUNT_LIMIT
  269. if (bootlimit && (bootcount > bootlimit)) {
  270. printf("Warning: Bootlimit (%u) exceeded. Using altbootcmd.\n",
  271. (unsigned)bootlimit);
  272. s = getenv("altbootcmd");
  273. } else
  274. #endif /* CONFIG_BOOTCOUNT_LIMIT */
  275. s = getenv("bootcmd");
  276. #ifdef CONFIG_OF_CONTROL
  277. /* Allow the fdt to override the boot command */
  278. env = fdtdec_get_config_string(gd->fdt_blob, "bootcmd");
  279. if (env)
  280. s = env;
  281. process_fdt_options(gd->fdt_blob);
  282. /*
  283. * If the bootsecure option was chosen, use secure_boot_cmd().
  284. * Always use 'env' in this case, since bootsecure requres that the
  285. * bootcmd was specified in the FDT too.
  286. */
  287. if (fdtdec_get_config_int(gd->fdt_blob, "bootsecure", 0))
  288. secure_boot_cmd(env);
  289. #endif /* CONFIG_OF_CONTROL */
  290. debug("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>");
  291. if (bootdelay != -1 && s && !abortboot(bootdelay)) {
  292. #if defined(CONFIG_AUTOBOOT_KEYED) && !defined(CONFIG_AUTOBOOT_KEYED_CTRLC)
  293. int prev = disable_ctrlc(1); /* disable Control C checking */
  294. #endif
  295. run_command_list(s, -1, 0);
  296. #if defined(CONFIG_AUTOBOOT_KEYED) && !defined(CONFIG_AUTOBOOT_KEYED_CTRLC)
  297. disable_ctrlc(prev); /* restore Control C checking */
  298. #endif
  299. }
  300. #ifdef CONFIG_MENUKEY
  301. if (menukey == CONFIG_MENUKEY) {
  302. s = getenv("menucmd");
  303. if (s)
  304. run_command_list(s, -1, 0);
  305. }
  306. #endif /* CONFIG_MENUKEY */
  307. }