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