]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
e7abe919 | 2 | /* |
53086653 | 3 | * (C) Copyright 2011-2013 Pali Rohár <[email protected]> |
e7abe919 T |
4 | */ |
5 | ||
a3d0aa87 | 6 | #include <charset.h> |
e7abe919 T |
7 | #include <common.h> |
8 | #include <command.h> | |
9 | #include <ansi.h> | |
c606c005 MK |
10 | #include <efi_loader.h> |
11 | #include <efi_variable.h> | |
7b51b576 | 12 | #include <env.h> |
f7ae49fc | 13 | #include <log.h> |
e7abe919 | 14 | #include <menu.h> |
e7abe919 T |
15 | #include <watchdog.h> |
16 | #include <malloc.h> | |
c05ed00a | 17 | #include <linux/delay.h> |
e7abe919 T |
18 | #include <linux/string.h> |
19 | ||
20 | /* maximum bootmenu entries */ | |
21 | #define MAX_COUNT 99 | |
22 | ||
23 | /* maximal size of bootmenu env | |
24 | * 9 = strlen("bootmenu_") | |
25 | * 2 = strlen(MAX_COUNT) | |
26 | * 1 = NULL term | |
27 | */ | |
28 | #define MAX_ENV_SIZE (9 + 2 + 1) | |
29 | ||
2158b0da MK |
30 | enum bootmenu_ret { |
31 | BOOTMENU_RET_SUCCESS = 0, | |
32 | BOOTMENU_RET_FAIL, | |
33 | BOOTMENU_RET_QUIT, | |
34 | BOOTMENU_RET_UPDATED, | |
35 | }; | |
36 | ||
a3d0aa87 MK |
37 | enum boot_type { |
38 | BOOTMENU_TYPE_NONE = 0, | |
39 | BOOTMENU_TYPE_BOOTMENU, | |
c606c005 | 40 | BOOTMENU_TYPE_UEFI_BOOT_OPTION, |
a3d0aa87 MK |
41 | }; |
42 | ||
e7abe919 T |
43 | struct bootmenu_entry { |
44 | unsigned short int num; /* unique number 0 .. MAX_COUNT */ | |
45 | char key[3]; /* key identifier of number */ | |
e85727dd | 46 | char *title; /* title of entry */ |
e7abe919 | 47 | char *command; /* hush command of entry */ |
a3d0aa87 MK |
48 | enum boot_type type; /* boot type of entry */ |
49 | u16 bootorder; /* order for each boot type */ | |
e7abe919 T |
50 | struct bootmenu_data *menu; /* this bootmenu */ |
51 | struct bootmenu_entry *next; /* next menu entry (num+1) */ | |
52 | }; | |
53 | ||
e7abe919 T |
54 | static char *bootmenu_getoption(unsigned short int n) |
55 | { | |
0eb33ad2 | 56 | char name[MAX_ENV_SIZE]; |
e7abe919 T |
57 | |
58 | if (n > MAX_COUNT) | |
59 | return NULL; | |
60 | ||
0eb33ad2 | 61 | sprintf(name, "bootmenu_%d", n); |
00caae6d | 62 | return env_get(name); |
e7abe919 T |
63 | } |
64 | ||
65 | static void bootmenu_print_entry(void *data) | |
66 | { | |
67 | struct bootmenu_entry *entry = data; | |
68 | int reverse = (entry->menu->active == entry->num); | |
69 | ||
70 | /* | |
71 | * Move cursor to line where the entry will be drown (entry->num) | |
72 | * First 3 lines contain bootmenu header + 1 empty line | |
73 | */ | |
d1d7ed7b | 74 | printf(ANSI_CURSOR_POSITION, entry->num + 4, 7); |
e7abe919 T |
75 | |
76 | if (reverse) | |
77 | puts(ANSI_COLOR_REVERSE); | |
78 | ||
e85727dd | 79 | printf("%s", entry->title); |
e7abe919 T |
80 | |
81 | if (reverse) | |
82 | puts(ANSI_COLOR_RESET); | |
83 | } | |
84 | ||
e7abe919 T |
85 | static char *bootmenu_choice_entry(void *data) |
86 | { | |
87 | struct bootmenu_data *menu = data; | |
88 | struct bootmenu_entry *iter; | |
89 | enum bootmenu_key key = KEY_NONE; | |
90 | int esc = 0; | |
91 | int i; | |
92 | ||
93 | while (1) { | |
94 | if (menu->delay >= 0) { | |
95 | /* Autoboot was not stopped */ | |
96 | bootmenu_autoboot_loop(menu, &key, &esc); | |
97 | } else { | |
98 | /* Some key was pressed, so autoboot was stopped */ | |
99 | bootmenu_loop(menu, &key, &esc); | |
100 | } | |
101 | ||
102 | switch (key) { | |
103 | case KEY_UP: | |
104 | if (menu->active > 0) | |
105 | --menu->active; | |
106 | /* no menu key selected, regenerate menu */ | |
107 | return NULL; | |
108 | case KEY_DOWN: | |
109 | if (menu->active < menu->count - 1) | |
110 | ++menu->active; | |
111 | /* no menu key selected, regenerate menu */ | |
112 | return NULL; | |
113 | case KEY_SELECT: | |
114 | iter = menu->first; | |
115 | for (i = 0; i < menu->active; ++i) | |
116 | iter = iter->next; | |
117 | return iter->key; | |
83a287a6 T |
118 | case KEY_QUIT: |
119 | /* Quit by choosing the last entry - U-Boot console */ | |
120 | iter = menu->first; | |
121 | while (iter->next) | |
122 | iter = iter->next; | |
123 | return iter->key; | |
e7abe919 T |
124 | default: |
125 | break; | |
126 | } | |
127 | } | |
128 | ||
129 | /* never happens */ | |
130 | debug("bootmenu: this should not happen"); | |
131 | return NULL; | |
132 | } | |
133 | ||
134 | static void bootmenu_destroy(struct bootmenu_data *menu) | |
135 | { | |
136 | struct bootmenu_entry *iter = menu->first; | |
137 | struct bootmenu_entry *next; | |
138 | ||
139 | while (iter) { | |
140 | next = iter->next; | |
141 | free(iter->title); | |
142 | free(iter->command); | |
143 | free(iter); | |
144 | iter = next; | |
145 | } | |
146 | free(menu); | |
147 | } | |
148 | ||
a3d0aa87 MK |
149 | /** |
150 | * prepare_bootmenu_entry() - generate the bootmenu_xx entries | |
151 | * | |
152 | * This function read the "bootmenu_x" U-Boot environment variable | |
153 | * and generate the bootmenu entries. | |
154 | * | |
155 | * @menu: pointer to the bootmenu structure | |
156 | * @current: pointer to the last bootmenu entry list | |
157 | * @index: pointer to the index of the last bootmenu entry, | |
158 | * the number of bootmenu entry is added by this function | |
159 | * Return: 1 on success, negative value on error | |
160 | */ | |
161 | static int prepare_bootmenu_entry(struct bootmenu_data *menu, | |
162 | struct bootmenu_entry **current, | |
163 | unsigned short int *index) | |
e7abe919 | 164 | { |
e7abe919 | 165 | char *sep; |
a3d0aa87 MK |
166 | const char *option; |
167 | unsigned short int i = *index; | |
168 | struct bootmenu_entry *entry = NULL; | |
169 | struct bootmenu_entry *iter = *current; | |
f7bb20a5 | 170 | |
e7abe919 | 171 | while ((option = bootmenu_getoption(i))) { |
a3d0aa87 | 172 | |
e85727dd | 173 | /* bootmenu_[num] format is "[title]=[commands]" */ |
e7abe919 T |
174 | sep = strchr(option, '='); |
175 | if (!sep) { | |
176 | printf("Invalid bootmenu entry: %s\n", option); | |
177 | break; | |
178 | } | |
179 | ||
180 | entry = malloc(sizeof(struct bootmenu_entry)); | |
181 | if (!entry) | |
a3d0aa87 | 182 | return -ENOMEM; |
e7abe919 | 183 | |
e85727dd | 184 | entry->title = strndup(option, sep - option); |
e7abe919 T |
185 | if (!entry->title) { |
186 | free(entry); | |
a3d0aa87 | 187 | return -ENOMEM; |
e7abe919 | 188 | } |
e7abe919 | 189 | |
e85727dd | 190 | entry->command = strdup(sep + 1); |
e7abe919 T |
191 | if (!entry->command) { |
192 | free(entry->title); | |
193 | free(entry); | |
a3d0aa87 | 194 | return -ENOMEM; |
e7abe919 | 195 | } |
e7abe919 T |
196 | |
197 | sprintf(entry->key, "%d", i); | |
198 | ||
199 | entry->num = i; | |
200 | entry->menu = menu; | |
a3d0aa87 MK |
201 | entry->type = BOOTMENU_TYPE_BOOTMENU; |
202 | entry->bootorder = i; | |
e7abe919 T |
203 | entry->next = NULL; |
204 | ||
205 | if (!iter) | |
206 | menu->first = entry; | |
207 | else | |
208 | iter->next = entry; | |
209 | ||
210 | iter = entry; | |
211 | ++i; | |
212 | ||
213 | if (i == MAX_COUNT - 1) | |
214 | break; | |
215 | } | |
216 | ||
a3d0aa87 MK |
217 | *index = i; |
218 | *current = iter; | |
219 | ||
220 | return 1; | |
221 | } | |
222 | ||
e85727dd | 223 | #if (CONFIG_IS_ENABLED(CMD_BOOTEFI_BOOTMGR)) |
c606c005 MK |
224 | /** |
225 | * prepare_uefi_bootorder_entry() - generate the uefi bootmenu entries | |
226 | * | |
227 | * This function read the "BootOrder" UEFI variable | |
228 | * and generate the bootmenu entries in the order of "BootOrder". | |
229 | * | |
230 | * @menu: pointer to the bootmenu structure | |
231 | * @current: pointer to the last bootmenu entry list | |
232 | * @index: pointer to the index of the last bootmenu entry, | |
233 | * the number of uefi entry is added by this function | |
234 | * Return: 1 on success, negative value on error | |
235 | */ | |
236 | static int prepare_uefi_bootorder_entry(struct bootmenu_data *menu, | |
237 | struct bootmenu_entry **current, | |
238 | unsigned short int *index) | |
239 | { | |
240 | u16 *bootorder; | |
241 | efi_status_t ret; | |
242 | unsigned short j; | |
243 | efi_uintn_t num, size; | |
244 | void *load_option; | |
245 | struct efi_load_option lo; | |
246 | u16 varname[] = u"Boot####"; | |
247 | unsigned short int i = *index; | |
248 | struct bootmenu_entry *entry = NULL; | |
249 | struct bootmenu_entry *iter = *current; | |
250 | ||
251 | bootorder = efi_get_var(u"BootOrder", &efi_global_variable_guid, &size); | |
252 | if (!bootorder) | |
253 | return -ENOENT; | |
254 | ||
255 | num = size / sizeof(u16); | |
256 | for (j = 0; j < num; j++) { | |
257 | entry = malloc(sizeof(struct bootmenu_entry)); | |
258 | if (!entry) | |
259 | return -ENOMEM; | |
260 | ||
261 | efi_create_indexed_name(varname, sizeof(varname), | |
262 | "Boot", bootorder[j]); | |
263 | load_option = efi_get_var(varname, &efi_global_variable_guid, &size); | |
264 | if (!load_option) | |
265 | continue; | |
266 | ||
267 | ret = efi_deserialize_load_option(&lo, load_option, &size); | |
268 | if (ret != EFI_SUCCESS) { | |
269 | log_warning("Invalid load option for %ls\n", varname); | |
270 | free(load_option); | |
271 | free(entry); | |
272 | continue; | |
273 | } | |
274 | ||
275 | if (lo.attributes & LOAD_OPTION_ACTIVE) { | |
e85727dd MK |
276 | char *buf; |
277 | ||
278 | buf = calloc(1, utf16_utf8_strlen(lo.label) + 1); | |
279 | if (!buf) { | |
c606c005 MK |
280 | free(load_option); |
281 | free(entry); | |
282 | free(bootorder); | |
283 | return -ENOMEM; | |
284 | } | |
e85727dd MK |
285 | entry->title = buf; |
286 | utf16_utf8_strncpy(&buf, lo.label, u16_strlen(lo.label)); | |
c606c005 MK |
287 | entry->command = strdup("bootefi bootmgr"); |
288 | sprintf(entry->key, "%d", i); | |
289 | entry->num = i; | |
290 | entry->menu = menu; | |
291 | entry->type = BOOTMENU_TYPE_UEFI_BOOT_OPTION; | |
292 | entry->bootorder = bootorder[j]; | |
293 | entry->next = NULL; | |
294 | ||
295 | if (!iter) | |
296 | menu->first = entry; | |
297 | else | |
298 | iter->next = entry; | |
299 | ||
300 | iter = entry; | |
301 | i++; | |
302 | } | |
303 | ||
304 | free(load_option); | |
305 | ||
306 | if (i == MAX_COUNT - 1) | |
307 | break; | |
308 | } | |
309 | ||
310 | free(bootorder); | |
311 | *index = i; | |
312 | *current = iter; | |
313 | ||
314 | return 1; | |
315 | } | |
e85727dd | 316 | #endif |
c606c005 | 317 | |
a3d0aa87 MK |
318 | static struct bootmenu_data *bootmenu_create(int delay) |
319 | { | |
320 | int ret; | |
321 | unsigned short int i = 0; | |
322 | struct bootmenu_data *menu; | |
323 | struct bootmenu_entry *iter = NULL; | |
324 | struct bootmenu_entry *entry; | |
325 | char *default_str; | |
326 | ||
327 | menu = malloc(sizeof(struct bootmenu_data)); | |
328 | if (!menu) | |
329 | return NULL; | |
330 | ||
331 | menu->delay = delay; | |
332 | menu->active = 0; | |
333 | menu->first = NULL; | |
334 | ||
335 | default_str = env_get("bootmenu_default"); | |
336 | if (default_str) | |
337 | menu->active = (int)simple_strtol(default_str, NULL, 10); | |
338 | ||
339 | ret = prepare_bootmenu_entry(menu, &iter, &i); | |
340 | if (ret < 0) | |
341 | goto cleanup; | |
342 | ||
e85727dd MK |
343 | #if (CONFIG_IS_ENABLED(CMD_BOOTEFI_BOOTMGR)) |
344 | if (i < MAX_COUNT - 1) { | |
c606c005 MK |
345 | ret = prepare_uefi_bootorder_entry(menu, &iter, &i); |
346 | if (ret < 0 && ret != -ENOENT) | |
347 | goto cleanup; | |
c606c005 | 348 | } |
e85727dd | 349 | #endif |
c606c005 | 350 | |
e7abe919 T |
351 | /* Add U-Boot console entry at the end */ |
352 | if (i <= MAX_COUNT - 1) { | |
353 | entry = malloc(sizeof(struct bootmenu_entry)); | |
354 | if (!entry) | |
355 | goto cleanup; | |
356 | ||
2158b0da | 357 | /* Add Quit entry if entering U-Boot console is disabled */ |
83f73632 | 358 | if (!IS_ENABLED(CONFIG_BOOTMENU_DISABLE_UBOOT_CONSOLE)) |
e85727dd | 359 | entry->title = strdup("U-Boot console"); |
2158b0da | 360 | else |
e85727dd | 361 | entry->title = strdup("Quit"); |
2158b0da | 362 | |
e7abe919 T |
363 | if (!entry->title) { |
364 | free(entry); | |
365 | goto cleanup; | |
366 | } | |
367 | ||
368 | entry->command = strdup(""); | |
369 | if (!entry->command) { | |
370 | free(entry->title); | |
371 | free(entry); | |
372 | goto cleanup; | |
373 | } | |
374 | ||
375 | sprintf(entry->key, "%d", i); | |
376 | ||
377 | entry->num = i; | |
378 | entry->menu = menu; | |
a3d0aa87 | 379 | entry->type = BOOTMENU_TYPE_NONE; |
e7abe919 T |
380 | entry->next = NULL; |
381 | ||
382 | if (!iter) | |
383 | menu->first = entry; | |
384 | else | |
385 | iter->next = entry; | |
386 | ||
387 | iter = entry; | |
388 | ++i; | |
389 | } | |
390 | ||
391 | menu->count = i; | |
bace2217 FW |
392 | |
393 | if ((menu->active >= menu->count)||(menu->active < 0)) { //ensure active menuitem is inside menu | |
394 | printf("active menuitem (%d) is outside menu (0..%d)\n",menu->active,menu->count-1); | |
395 | menu->active=0; | |
396 | } | |
397 | ||
e7abe919 T |
398 | return menu; |
399 | ||
400 | cleanup: | |
401 | bootmenu_destroy(menu); | |
402 | return NULL; | |
403 | } | |
404 | ||
5168d7a6 TA |
405 | static void menu_display_statusline(struct menu *m) |
406 | { | |
407 | struct bootmenu_entry *entry; | |
408 | struct bootmenu_data *menu; | |
409 | ||
410 | if (menu_default_choice(m, (void *)&entry) < 0) | |
411 | return; | |
412 | ||
413 | menu = entry->menu; | |
414 | ||
415 | printf(ANSI_CURSOR_POSITION, 1, 1); | |
416 | puts(ANSI_CLEAR_LINE); | |
d1d7ed7b HS |
417 | printf(ANSI_CURSOR_POSITION, 2, 3); |
418 | puts("*** U-Boot Boot Menu ***"); | |
5168d7a6 TA |
419 | puts(ANSI_CLEAR_LINE_TO_END); |
420 | printf(ANSI_CURSOR_POSITION, 3, 1); | |
421 | puts(ANSI_CLEAR_LINE); | |
422 | ||
423 | /* First 3 lines are bootmenu header + 2 empty lines between entries */ | |
424 | printf(ANSI_CURSOR_POSITION, menu->count + 5, 1); | |
425 | puts(ANSI_CLEAR_LINE); | |
d1d7ed7b HS |
426 | printf(ANSI_CURSOR_POSITION, menu->count + 6, 3); |
427 | puts("Press UP/DOWN to move, ENTER to select, ESC/CTRL+C to quit"); | |
5168d7a6 TA |
428 | puts(ANSI_CLEAR_LINE_TO_END); |
429 | printf(ANSI_CURSOR_POSITION, menu->count + 7, 1); | |
430 | puts(ANSI_CLEAR_LINE); | |
431 | } | |
432 | ||
c606c005 MK |
433 | static void handle_uefi_bootnext(void) |
434 | { | |
435 | u16 bootnext; | |
436 | efi_status_t ret; | |
437 | efi_uintn_t size; | |
438 | ||
439 | /* Initialize EFI drivers */ | |
440 | ret = efi_init_obj_list(); | |
441 | if (ret != EFI_SUCCESS) { | |
442 | log_err("Error: Cannot initialize UEFI sub-system, r = %lu\n", | |
443 | ret & ~EFI_ERROR_MASK); | |
444 | ||
445 | return; | |
446 | } | |
447 | ||
448 | /* If UEFI BootNext variable is set, boot the BootNext load option */ | |
449 | size = sizeof(u16); | |
450 | ret = efi_get_variable_int(u"BootNext", | |
451 | &efi_global_variable_guid, | |
452 | NULL, &size, &bootnext, NULL); | |
453 | if (ret == EFI_SUCCESS) | |
454 | /* BootNext does exist here, try to boot */ | |
455 | run_command("bootefi bootmgr", 0); | |
456 | } | |
457 | ||
2158b0da | 458 | static enum bootmenu_ret bootmenu_show(int delay) |
e7abe919 | 459 | { |
2158b0da | 460 | int cmd_ret; |
e7abe919 T |
461 | int init = 0; |
462 | void *choice = NULL; | |
e85727dd | 463 | char *title = NULL; |
e7abe919 T |
464 | char *command = NULL; |
465 | struct menu *menu; | |
e7abe919 | 466 | struct bootmenu_entry *iter; |
2158b0da MK |
467 | int ret = BOOTMENU_RET_SUCCESS; |
468 | struct bootmenu_data *bootmenu; | |
c606c005 | 469 | efi_status_t efi_ret = EFI_SUCCESS; |
e7abe919 T |
470 | char *option, *sep; |
471 | ||
c606c005 MK |
472 | if (IS_ENABLED(CONFIG_CMD_BOOTEFI_BOOTMGR)) |
473 | handle_uefi_bootnext(); | |
474 | ||
e7abe919 T |
475 | /* If delay is 0 do not create menu, just run first entry */ |
476 | if (delay == 0) { | |
477 | option = bootmenu_getoption(0); | |
478 | if (!option) { | |
479 | puts("bootmenu option 0 was not found\n"); | |
2158b0da | 480 | return BOOTMENU_RET_FAIL; |
e7abe919 T |
481 | } |
482 | sep = strchr(option, '='); | |
483 | if (!sep) { | |
484 | puts("bootmenu option 0 is invalid\n"); | |
2158b0da | 485 | return BOOTMENU_RET_FAIL; |
e7abe919 | 486 | } |
2158b0da MK |
487 | cmd_ret = run_command(sep + 1, 0); |
488 | return (cmd_ret == CMD_RET_SUCCESS ? BOOTMENU_RET_SUCCESS : BOOTMENU_RET_FAIL); | |
e7abe919 T |
489 | } |
490 | ||
491 | bootmenu = bootmenu_create(delay); | |
492 | if (!bootmenu) | |
2158b0da | 493 | return BOOTMENU_RET_FAIL; |
e7abe919 | 494 | |
5168d7a6 TA |
495 | menu = menu_create(NULL, bootmenu->delay, 1, menu_display_statusline, |
496 | bootmenu_print_entry, bootmenu_choice_entry, | |
497 | bootmenu); | |
e7abe919 T |
498 | if (!menu) { |
499 | bootmenu_destroy(bootmenu); | |
2158b0da | 500 | return BOOTMENU_RET_FAIL; |
e7abe919 T |
501 | } |
502 | ||
503 | for (iter = bootmenu->first; iter; iter = iter->next) { | |
990f6636 | 504 | if (menu_item_add(menu, iter->key, iter) != 1) |
e7abe919 T |
505 | goto cleanup; |
506 | } | |
507 | ||
508 | /* Default menu entry is always first */ | |
509 | menu_default_set(menu, "0"); | |
510 | ||
511 | puts(ANSI_CURSOR_HIDE); | |
512 | puts(ANSI_CLEAR_CONSOLE); | |
513 | printf(ANSI_CURSOR_POSITION, 1, 1); | |
514 | ||
515 | init = 1; | |
516 | ||
990f6636 | 517 | if (menu_get_choice(menu, &choice) == 1) { |
e7abe919 | 518 | iter = choice; |
e85727dd | 519 | title = strdup(iter->title); |
e7abe919 | 520 | command = strdup(iter->command); |
2158b0da MK |
521 | |
522 | /* last entry is U-Boot console or Quit */ | |
523 | if (iter->num == iter->menu->count - 1) { | |
524 | ret = BOOTMENU_RET_QUIT; | |
525 | goto cleanup; | |
526 | } | |
527 | } else { | |
528 | goto cleanup; | |
e7abe919 T |
529 | } |
530 | ||
c606c005 MK |
531 | /* |
532 | * If the selected entry is UEFI BOOT####, set the BootNext variable. | |
533 | * Then uefi bootmgr is invoked by the preset command in iter->command. | |
534 | */ | |
535 | if (IS_ENABLED(CONFIG_CMD_BOOTEFI_BOOTMGR)) { | |
536 | if (iter->type == BOOTMENU_TYPE_UEFI_BOOT_OPTION) { | |
537 | /* | |
538 | * UEFI specification requires BootNext variable needs non-volatile | |
539 | * attribute, but this BootNext is only used inside of U-Boot and | |
540 | * removed by efi bootmgr once BootNext is processed. | |
541 | * So this BootNext can be volatile. | |
542 | */ | |
543 | efi_ret = efi_set_variable_int(u"BootNext", &efi_global_variable_guid, | |
544 | EFI_VARIABLE_BOOTSERVICE_ACCESS | | |
545 | EFI_VARIABLE_RUNTIME_ACCESS, | |
546 | sizeof(u16), &iter->bootorder, false); | |
547 | if (efi_ret != EFI_SUCCESS) | |
548 | goto cleanup; | |
549 | } | |
550 | } | |
551 | ||
e7abe919 T |
552 | cleanup: |
553 | menu_destroy(menu); | |
554 | bootmenu_destroy(bootmenu); | |
555 | ||
556 | if (init) { | |
557 | puts(ANSI_CURSOR_SHOW); | |
558 | puts(ANSI_CLEAR_CONSOLE); | |
559 | printf(ANSI_CURSOR_POSITION, 1, 1); | |
560 | } | |
561 | ||
562 | if (title && command) { | |
e85727dd | 563 | debug("Starting entry '%s'\n", title); |
e7abe919 | 564 | free(title); |
c606c005 | 565 | if (efi_ret == EFI_SUCCESS) |
2158b0da | 566 | cmd_ret = run_command(command, 0); |
e7abe919 T |
567 | free(command); |
568 | } | |
569 | ||
570 | #ifdef CONFIG_POSTBOOTMENU | |
571 | run_command(CONFIG_POSTBOOTMENU, 0); | |
572 | #endif | |
2158b0da MK |
573 | |
574 | if (efi_ret != EFI_SUCCESS || cmd_ret != CMD_RET_SUCCESS) | |
575 | ret = BOOTMENU_RET_FAIL; | |
576 | ||
577 | return ret; | |
e7abe919 T |
578 | } |
579 | ||
e231306e | 580 | #ifdef CONFIG_AUTOBOOT_MENU_SHOW |
e7abe919 T |
581 | int menu_show(int bootdelay) |
582 | { | |
2158b0da MK |
583 | int ret; |
584 | ||
585 | while (1) { | |
586 | ret = bootmenu_show(bootdelay); | |
587 | bootdelay = -1; | |
588 | if (ret == BOOTMENU_RET_UPDATED) | |
589 | continue; | |
590 | ||
83f73632 | 591 | if (IS_ENABLED(CONFIG_BOOTMENU_DISABLE_UBOOT_CONSOLE)) { |
2158b0da MK |
592 | if (ret == BOOTMENU_RET_QUIT) { |
593 | /* default boot process */ | |
594 | if (IS_ENABLED(CONFIG_CMD_BOOTEFI_BOOTMGR)) | |
595 | run_command("bootefi bootmgr", 0); | |
596 | ||
597 | run_command("run bootcmd", 0); | |
598 | } | |
599 | } else { | |
600 | break; | |
601 | } | |
602 | } | |
603 | ||
e7abe919 T |
604 | return -1; /* -1 - abort boot and run monitor code */ |
605 | } | |
606 | #endif | |
607 | ||
09140113 | 608 | int do_bootmenu(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) |
e7abe919 T |
609 | { |
610 | char *delay_str = NULL; | |
611 | int delay = 10; | |
612 | ||
613 | #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0) | |
614 | delay = CONFIG_BOOTDELAY; | |
615 | #endif | |
616 | ||
617 | if (argc >= 2) | |
618 | delay_str = argv[1]; | |
619 | ||
620 | if (!delay_str) | |
00caae6d | 621 | delay_str = env_get("bootmenu_delay"); |
e7abe919 T |
622 | |
623 | if (delay_str) | |
624 | delay = (int)simple_strtol(delay_str, NULL, 10); | |
625 | ||
626 | bootmenu_show(delay); | |
627 | return 0; | |
628 | } | |
629 | ||
630 | U_BOOT_CMD( | |
631 | bootmenu, 2, 1, do_bootmenu, | |
632 | "ANSI terminal bootmenu", | |
633 | "[delay]\n" | |
634 | " - show ANSI terminal bootmenu with autoboot delay" | |
635 | ); |