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 #include <common.h> 9 #include <bootretry.h> 10 #include <cli.h> 11 #include <fdtdec.h> 12 #include <menu.h> 13 #include <post.h> 14 15 DECLARE_GLOBAL_DATA_PTR; 16 17 #define MAX_DELAY_STOP_STR 32 18 19 #ifndef DEBUG_BOOTKEYS 20 #define DEBUG_BOOTKEYS 0 21 #endif 22 #define debug_bootkeys(fmt, args...) \ 23 debug_cond(DEBUG_BOOTKEYS, fmt, ##args) 24 25 /* Stored value of bootdelay, used by autoboot_command() */ 26 static int stored_bootdelay; 27 28 /*************************************************************************** 29 * Watch for 'delay' seconds for autoboot stop or autoboot delay string. 30 * returns: 0 - no key string, allow autoboot 1 - got key string, abort 31 */ 32 # if defined(CONFIG_AUTOBOOT_KEYED) 33 static int abortboot_keyed(int bootdelay) 34 { 35 int abort = 0; 36 uint64_t etime = endtick(bootdelay); 37 struct { 38 char *str; 39 u_int len; 40 int retry; 41 } 42 delaykey[] = { 43 { .str = getenv("bootdelaykey"), .retry = 1 }, 44 { .str = getenv("bootdelaykey2"), .retry = 1 }, 45 { .str = getenv("bootstopkey"), .retry = 0 }, 46 { .str = getenv("bootstopkey2"), .retry = 0 }, 47 }; 48 49 char presskey[MAX_DELAY_STOP_STR]; 50 u_int presskey_len = 0; 51 u_int presskey_max = 0; 52 u_int i; 53 54 #ifndef CONFIG_ZERO_BOOTDELAY_CHECK 55 if (bootdelay == 0) 56 return 0; 57 #endif 58 59 # ifdef CONFIG_AUTOBOOT_PROMPT 60 printf(CONFIG_AUTOBOOT_PROMPT); 61 # endif 62 63 # ifdef CONFIG_AUTOBOOT_DELAY_STR 64 if (delaykey[0].str == NULL) 65 delaykey[0].str = CONFIG_AUTOBOOT_DELAY_STR; 66 # endif 67 # ifdef CONFIG_AUTOBOOT_DELAY_STR2 68 if (delaykey[1].str == NULL) 69 delaykey[1].str = CONFIG_AUTOBOOT_DELAY_STR2; 70 # endif 71 # ifdef CONFIG_AUTOBOOT_STOP_STR 72 if (delaykey[2].str == NULL) 73 delaykey[2].str = CONFIG_AUTOBOOT_STOP_STR; 74 # endif 75 # ifdef CONFIG_AUTOBOOT_STOP_STR2 76 if (delaykey[3].str == NULL) 77 delaykey[3].str = CONFIG_AUTOBOOT_STOP_STR2; 78 # endif 79 80 for (i = 0; i < sizeof(delaykey) / sizeof(delaykey[0]); i++) { 81 delaykey[i].len = delaykey[i].str == NULL ? 82 0 : strlen(delaykey[i].str); 83 delaykey[i].len = delaykey[i].len > MAX_DELAY_STOP_STR ? 84 MAX_DELAY_STOP_STR : delaykey[i].len; 85 86 presskey_max = presskey_max > delaykey[i].len ? 87 presskey_max : delaykey[i].len; 88 89 debug_bootkeys("%s key:<%s>\n", 90 delaykey[i].retry ? "delay" : "stop", 91 delaykey[i].str ? delaykey[i].str : "NULL"); 92 } 93 94 /* In order to keep up with incoming data, check timeout only 95 * when catch up. 96 */ 97 do { 98 if (tstc()) { 99 if (presskey_len < presskey_max) { 100 presskey[presskey_len++] = getc(); 101 } else { 102 for (i = 0; i < presskey_max - 1; i++) 103 presskey[i] = presskey[i + 1]; 104 105 presskey[i] = getc(); 106 } 107 } 108 109 for (i = 0; i < sizeof(delaykey) / sizeof(delaykey[0]); i++) { 110 if (delaykey[i].len > 0 && 111 presskey_len >= delaykey[i].len && 112 memcmp(presskey + presskey_len - 113 delaykey[i].len, delaykey[i].str, 114 delaykey[i].len) == 0) { 115 debug_bootkeys("got %skey\n", 116 delaykey[i].retry ? "delay" : 117 "stop"); 118 119 /* don't retry auto boot */ 120 if (!delaykey[i].retry) 121 bootretry_dont_retry(); 122 abort = 1; 123 } 124 } 125 } while (!abort && get_ticks() <= etime); 126 127 if (!abort) 128 debug_bootkeys("key timeout\n"); 129 130 #ifdef CONFIG_SILENT_CONSOLE 131 if (abort) 132 gd->flags &= ~GD_FLG_SILENT; 133 #endif 134 135 return abort; 136 } 137 138 # else /* !defined(CONFIG_AUTOBOOT_KEYED) */ 139 140 #ifdef CONFIG_MENUKEY 141 static int menukey; 142 #endif 143 144 static int abortboot_normal(int bootdelay) 145 { 146 int abort = 0; 147 unsigned long ts; 148 149 #ifdef CONFIG_MENUPROMPT 150 printf(CONFIG_MENUPROMPT); 151 #else 152 if (bootdelay >= 0) 153 printf("Hit any key to stop autoboot: %2d ", bootdelay); 154 #endif 155 156 #if defined CONFIG_ZERO_BOOTDELAY_CHECK 157 /* 158 * Check if key already pressed 159 * Don't check if bootdelay < 0 160 */ 161 if (bootdelay >= 0) { 162 if (tstc()) { /* we got a key press */ 163 (void) getc(); /* consume input */ 164 puts("\b\b\b 0"); 165 abort = 1; /* don't auto boot */ 166 } 167 } 168 #endif 169 170 while ((bootdelay > 0) && (!abort)) { 171 --bootdelay; 172 /* delay 1000 ms */ 173 ts = get_timer(0); 174 do { 175 if (tstc()) { /* we got a key press */ 176 abort = 1; /* don't auto boot */ 177 bootdelay = 0; /* no more delay */ 178 # ifdef CONFIG_MENUKEY 179 menukey = getc(); 180 # else 181 (void) getc(); /* consume input */ 182 # endif 183 break; 184 } 185 udelay(10000); 186 } while (!abort && get_timer(ts) < 1000); 187 188 printf("\b\b\b%2d ", bootdelay); 189 } 190 191 putc('\n'); 192 193 #ifdef CONFIG_SILENT_CONSOLE 194 if (abort) 195 gd->flags &= ~GD_FLG_SILENT; 196 #endif 197 198 return abort; 199 } 200 # endif /* CONFIG_AUTOBOOT_KEYED */ 201 202 static int abortboot(int bootdelay) 203 { 204 #ifdef CONFIG_AUTOBOOT_KEYED 205 return abortboot_keyed(bootdelay); 206 #else 207 return abortboot_normal(bootdelay); 208 #endif 209 } 210 211 static void process_fdt_options(const void *blob) 212 { 213 #if defined(CONFIG_OF_CONTROL) 214 ulong addr; 215 216 /* Add an env variable to point to a kernel payload, if available */ 217 addr = fdtdec_get_config_int(gd->fdt_blob, "kernel-offset", 0); 218 if (addr) 219 setenv_addr("kernaddr", (void *)(CONFIG_SYS_TEXT_BASE + addr)); 220 221 /* Add an env variable to point to a root disk, if available */ 222 addr = fdtdec_get_config_int(gd->fdt_blob, "rootdisk-offset", 0); 223 if (addr) 224 setenv_addr("rootaddr", (void *)(CONFIG_SYS_TEXT_BASE + addr)); 225 #endif /* CONFIG_OF_CONTROL */ 226 } 227 228 const char *bootdelay_process(void) 229 { 230 char *s; 231 int bootdelay; 232 #ifdef CONFIG_BOOTCOUNT_LIMIT 233 unsigned long bootcount = 0; 234 unsigned long bootlimit = 0; 235 #endif /* CONFIG_BOOTCOUNT_LIMIT */ 236 237 #ifdef CONFIG_BOOTCOUNT_LIMIT 238 bootcount = bootcount_load(); 239 bootcount++; 240 bootcount_store(bootcount); 241 setenv_ulong("bootcount", bootcount); 242 bootlimit = getenv_ulong("bootlimit", 10, 0); 243 #endif /* CONFIG_BOOTCOUNT_LIMIT */ 244 245 s = getenv("bootdelay"); 246 bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY; 247 248 #ifdef CONFIG_OF_CONTROL 249 bootdelay = fdtdec_get_config_int(gd->fdt_blob, "bootdelay", 250 bootdelay); 251 #endif 252 253 debug("### main_loop entered: bootdelay=%d\n\n", bootdelay); 254 255 #if defined(CONFIG_MENU_SHOW) 256 bootdelay = menu_show(bootdelay); 257 #endif 258 bootretry_init_cmd_timeout(); 259 260 #ifdef CONFIG_POST 261 if (gd->flags & GD_FLG_POSTFAIL) { 262 s = getenv("failbootcmd"); 263 } else 264 #endif /* CONFIG_POST */ 265 #ifdef CONFIG_BOOTCOUNT_LIMIT 266 if (bootlimit && (bootcount > bootlimit)) { 267 printf("Warning: Bootlimit (%u) exceeded. Using altbootcmd.\n", 268 (unsigned)bootlimit); 269 s = getenv("altbootcmd"); 270 } else 271 #endif /* CONFIG_BOOTCOUNT_LIMIT */ 272 s = getenv("bootcmd"); 273 274 process_fdt_options(gd->fdt_blob); 275 stored_bootdelay = bootdelay; 276 277 return s; 278 } 279 280 void autoboot_command(const char *s) 281 { 282 debug("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>"); 283 284 if (stored_bootdelay != -1 && s && !abortboot(stored_bootdelay)) { 285 #if defined(CONFIG_AUTOBOOT_KEYED) && !defined(CONFIG_AUTOBOOT_KEYED_CTRLC) 286 int prev = disable_ctrlc(1); /* disable Control C checking */ 287 #endif 288 289 run_command_list(s, -1, 0); 290 291 #if defined(CONFIG_AUTOBOOT_KEYED) && !defined(CONFIG_AUTOBOOT_KEYED_CTRLC) 292 disable_ctrlc(prev); /* restore Control C checking */ 293 #endif 294 } 295 296 #ifdef CONFIG_MENUKEY 297 if (menukey == CONFIG_MENUKEY) { 298 s = getenv("menucmd"); 299 if (s) 300 run_command_list(s, -1, 0); 301 } 302 #endif /* CONFIG_MENUKEY */ 303 } 304