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