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