menu: Make use of CLI character processing
[platform/kernel/u-boot.git] / cmd / eficonfig.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  *  Menu-driven UEFI Variable maintenance
4  *
5  *  Copyright (c) 2022 Masahisa Kojima, Linaro Limited
6  */
7
8 #include <ansi.h>
9 #include <cli.h>
10 #include <common.h>
11 #include <charset.h>
12 #include <efi_loader.h>
13 #include <efi_load_initrd.h>
14 #include <efi_config.h>
15 #include <efi_variable.h>
16 #include <log.h>
17 #include <malloc.h>
18 #include <menu.h>
19 #include <sort.h>
20 #include <watchdog.h>
21 #include <asm/unaligned.h>
22 #include <linux/delay.h>
23
24 static struct efi_simple_text_input_protocol *cin;
25
26 #define EFICONFIG_DESCRIPTION_MAX 32
27 #define EFICONFIG_OPTIONAL_DATA_MAX 64
28
29 /**
30  * struct eficonfig_filepath_info - structure to be used to store file path
31  *
32  * @name:       file or directory name
33  * @list:       list structure
34  */
35 struct eficonfig_filepath_info {
36         char *name;
37         struct list_head list;
38 };
39
40 /**
41  * struct eficonfig_boot_option - structure to be used for updating UEFI boot option
42  *
43  * @file_info:          user selected file info
44  * @initrd_info:        user selected initrd file info
45  * @boot_index:         index of the boot option
46  * @description:        pointer to the description string
47  * @optional_data:      pointer to the optional_data
48  * @edit_completed:     flag indicates edit complete
49  */
50 struct eficonfig_boot_option {
51         struct eficonfig_select_file_info file_info;
52         struct eficonfig_select_file_info initrd_info;
53         unsigned int boot_index;
54         u16 *description;
55         u16 *optional_data;
56         bool edit_completed;
57 };
58
59 /**
60  * struct eficonfig_volume_entry_data - structure to be used to store volume info
61  *
62  * @file_info:  pointer to file info structure
63  * @v:          pointer to the protocol interface
64  * @dp:         pointer to the device path
65  */
66 struct eficonfig_volume_entry_data {
67         struct eficonfig_select_file_info *file_info;
68         struct efi_simple_file_system_protocol *v;
69         struct efi_device_path *dp;
70 };
71
72 /**
73  * struct eficonfig_file_entry_data - structure to be used to store file info
74  *
75  * @file_info:          pointer to file info structure
76  * @is_directory:       flag to identify the directory or file
77  * @file_name:          name of directory or file
78  */
79 struct eficonfig_file_entry_data {
80         struct eficonfig_select_file_info *file_info;
81         bool is_directory;
82         char *file_name;
83 };
84
85 /**
86  * struct eficonfig_boot_selection_data - structure to be used to select the boot option entry
87  *
88  * @boot_index: index of the boot option
89  * @selected:           pointer to store the selected index in the BootOrder variable
90  */
91 struct eficonfig_boot_selection_data {
92         u16 boot_index;
93         int *selected;
94 };
95
96 /**
97  * struct eficonfig_boot_order_data - structure to be used to update BootOrder variable
98  *
99  * @boot_index:         boot option index
100  * @active:             flag to include the boot option into BootOrder variable
101  */
102 struct eficonfig_boot_order_data {
103         u32 boot_index;
104         bool active;
105 };
106
107 /**
108  * eficonfig_print_msg() - print message
109  *
110  * display the message to the user, user proceeds the screen
111  * with any key press.
112  *
113  * @items:              pointer to the structure of each menu entry
114  * @count:              the number of menu entry
115  * @menu_header:        pointer to the menu header string
116  * Return:      status code
117  */
118 void eficonfig_print_msg(char *msg)
119 {
120         /* Flush input */
121         while (tstc())
122                 getchar();
123
124         printf(ANSI_CURSOR_HIDE
125                ANSI_CLEAR_CONSOLE
126                ANSI_CURSOR_POSITION
127                "%s\n\n  Press any key to continue", 3, 4, msg);
128
129         getchar();
130 }
131
132 /**
133  * eficonfig_print_entry() - print each menu entry
134  *
135  * @data:       pointer to the data associated with each menu entry
136  */
137 static void eficonfig_print_entry(void *data)
138 {
139         struct eficonfig_entry *entry = data;
140         int reverse = (entry->efi_menu->active == entry->num);
141
142         /* TODO: support scroll or page for many entries */
143
144         /*
145          * Move cursor to line where the entry will be drawn (entry->num)
146          * First 3 lines(menu header) + 1 empty line
147          */
148         printf(ANSI_CURSOR_POSITION, entry->num + 4, 7);
149
150         if (reverse)
151                 puts(ANSI_COLOR_REVERSE);
152
153         printf("%s", entry->title);
154
155         if (reverse)
156                 puts(ANSI_COLOR_RESET);
157 }
158
159 /**
160  * eficonfig_display_statusline() - print status line
161  *
162  * @m:  pointer to the menu structure
163  */
164 static void eficonfig_display_statusline(struct menu *m)
165 {
166         struct eficonfig_entry *entry;
167
168         if (menu_default_choice(m, (void *)&entry) < 0)
169                 return;
170
171         printf(ANSI_CURSOR_POSITION
172               "\n%s\n"
173                ANSI_CURSOR_POSITION ANSI_CLEAR_LINE ANSI_CURSOR_POSITION
174                "  Press UP/DOWN to move, ENTER to select, ESC/CTRL+C to quit"
175                ANSI_CLEAR_LINE_TO_END ANSI_CURSOR_POSITION ANSI_CLEAR_LINE,
176                1, 1, entry->efi_menu->menu_header, entry->efi_menu->count + 5, 1,
177                entry->efi_menu->count + 6, 1, entry->efi_menu->count + 7, 1);
178 }
179
180 /**
181  * eficonfig_choice_entry() - user key input handler
182  *
183  * @data:       pointer to the efimenu structure
184  * Return:      key string to identify the selected entry
185  */
186 static char *eficonfig_choice_entry(void *data)
187 {
188         struct cli_ch_state s_cch, *cch = &s_cch;
189         struct list_head *pos, *n;
190         struct eficonfig_entry *entry;
191         enum bootmenu_key key = BKEY_NONE;
192         struct efimenu *efi_menu = data;
193
194         cli_ch_init(cch);
195
196         while (1) {
197                 key = bootmenu_loop((struct bootmenu_data *)efi_menu, cch);
198
199                 switch (key) {
200                 case BKEY_UP:
201                         if (efi_menu->active > 0)
202                                 --efi_menu->active;
203                         /* no menu key selected, regenerate menu */
204                         return NULL;
205                 case BKEY_DOWN:
206                         if (efi_menu->active < efi_menu->count - 1)
207                                 ++efi_menu->active;
208                         /* no menu key selected, regenerate menu */
209                         return NULL;
210                 case BKEY_SELECT:
211                         list_for_each_safe(pos, n, &efi_menu->list) {
212                                 entry = list_entry(pos, struct eficonfig_entry, list);
213                                 if (entry->num == efi_menu->active)
214                                         return entry->key;
215                         }
216                         break;
217                 case BKEY_QUIT:
218                         /* Quit by choosing the last entry */
219                         entry = list_last_entry(&efi_menu->list, struct eficonfig_entry, list);
220                         return entry->key;
221                 default:
222                         /* Pressed key is not valid, no need to regenerate the menu */
223                         break;
224                 }
225         }
226 }
227
228 /**
229  * eficonfig_destroy() - destroy efimenu
230  *
231  * @efi_menu:   pointer to the efimenu structure
232  */
233 void eficonfig_destroy(struct efimenu *efi_menu)
234 {
235         struct list_head *pos, *n;
236         struct eficonfig_entry *entry;
237
238         if (!efi_menu)
239                 return;
240
241         list_for_each_safe(pos, n, &efi_menu->list) {
242                 entry = list_entry(pos, struct eficonfig_entry, list);
243                 free(entry->title);
244                 list_del(&entry->list);
245                 free(entry);
246         }
247         free(efi_menu->menu_header);
248         free(efi_menu);
249 }
250
251 /**
252  * eficonfig_process_quit() - callback function for "Quit" entry
253  *
254  * @data:       pointer to the data
255  * Return:      status code
256  */
257 efi_status_t eficonfig_process_quit(void *data)
258 {
259         return EFI_ABORTED;
260 }
261
262 /**
263  * eficonfig_append_menu_entry() - append menu item
264  *
265  * @efi_menu:   pointer to the efimenu structure
266  * @title:      pointer to the entry title
267  * @func:       callback of each entry
268  * @data:       pointer to the data to be passed to each entry callback
269  * Return:      status code
270  */
271 efi_status_t eficonfig_append_menu_entry(struct efimenu *efi_menu,
272                                          char *title, eficonfig_entry_func func,
273                                          void *data)
274 {
275         struct eficonfig_entry *entry;
276
277         if (efi_menu->count >= EFICONFIG_ENTRY_NUM_MAX)
278                 return EFI_OUT_OF_RESOURCES;
279
280         entry = calloc(1, sizeof(struct eficonfig_entry));
281         if (!entry)
282                 return EFI_OUT_OF_RESOURCES;
283
284         entry->title = title;
285         sprintf(entry->key, "%d", efi_menu->count);
286         entry->efi_menu = efi_menu;
287         entry->func = func;
288         entry->data = data;
289         entry->num = efi_menu->count++;
290         list_add_tail(&entry->list, &efi_menu->list);
291
292         return EFI_SUCCESS;
293 }
294
295 /**
296  * eficonfig_append_quit_entry() - append quit entry
297  *
298  * @efi_menu:   pointer to the efimenu structure
299  * Return:      status code
300  */
301 efi_status_t eficonfig_append_quit_entry(struct efimenu *efi_menu)
302 {
303         char *title;
304         efi_status_t ret;
305
306         title = strdup("Quit");
307         if (!title)
308                 return EFI_OUT_OF_RESOURCES;
309
310         ret = eficonfig_append_menu_entry(efi_menu, title, eficonfig_process_quit, NULL);
311         if (ret != EFI_SUCCESS)
312                 free(title);
313
314         return ret;
315 }
316
317 /**
318  * eficonfig_create_fixed_menu() - create fixed entry menu structure
319  *
320  * @items:      pointer to the menu entry item
321  * @count:      the number of menu entry
322  * Return:      pointer to the efimenu structure
323  */
324 void *eficonfig_create_fixed_menu(const struct eficonfig_item *items, int count)
325 {
326         u32 i;
327         char *title;
328         efi_status_t ret;
329         struct efimenu *efi_menu;
330         const struct eficonfig_item *iter = items;
331
332         efi_menu = calloc(1, sizeof(struct efimenu));
333         if (!efi_menu)
334                 return NULL;
335
336         INIT_LIST_HEAD(&efi_menu->list);
337         for (i = 0; i < count; i++, iter++) {
338                 title = strdup(iter->title);
339                 if (!title)
340                         goto out;
341
342                 ret = eficonfig_append_menu_entry(efi_menu, title, iter->func, iter->data);
343                 if (ret != EFI_SUCCESS) {
344                         free(title);
345                         goto out;
346                 }
347         }
348
349         return efi_menu;
350 out:
351         eficonfig_destroy(efi_menu);
352
353         return NULL;
354 }
355
356 /**
357  * eficonfig_process_common() - main handler for UEFI menu
358  *
359  * Construct the structures required to show the menu, then handle
360  * the user input interacting with u-boot menu functions.
361  *
362  * @efi_menu:           pointer to the efimenu structure
363  * @menu_header:        pointer to the menu header string
364  * Return:              status code
365  */
366 efi_status_t eficonfig_process_common(struct efimenu *efi_menu, char *menu_header)
367 {
368         struct menu *menu;
369         void *choice = NULL;
370         struct list_head *pos, *n;
371         struct eficonfig_entry *entry;
372         efi_status_t ret = EFI_SUCCESS;
373
374         if (efi_menu->count > EFICONFIG_ENTRY_NUM_MAX)
375                 return EFI_OUT_OF_RESOURCES;
376
377         efi_menu->delay = -1;
378         efi_menu->active = 0;
379
380         if (menu_header) {
381                 efi_menu->menu_header = strdup(menu_header);
382                 if (!efi_menu->menu_header)
383                         return EFI_OUT_OF_RESOURCES;
384         }
385
386         menu = menu_create(NULL, 0, 1, eficonfig_display_statusline,
387                            eficonfig_print_entry, eficonfig_choice_entry,
388                            efi_menu);
389         if (!menu)
390                 return EFI_INVALID_PARAMETER;
391
392         list_for_each_safe(pos, n, &efi_menu->list) {
393                 entry = list_entry(pos, struct eficonfig_entry, list);
394                 if (!menu_item_add(menu, entry->key, entry)) {
395                         ret = EFI_INVALID_PARAMETER;
396                         goto out;
397                 }
398         }
399
400         entry = list_first_entry_or_null(&efi_menu->list, struct eficonfig_entry, list);
401         if (entry)
402                 menu_default_set(menu, entry->key);
403
404         printf(ANSI_CURSOR_HIDE
405                ANSI_CLEAR_CONSOLE
406                ANSI_CURSOR_POSITION, 1, 1);
407
408         if (menu_get_choice(menu, &choice)) {
409                 entry = choice;
410                 if (entry->func)
411                         ret = entry->func(entry->data);
412         }
413 out:
414         menu_destroy(menu);
415
416         printf(ANSI_CLEAR_CONSOLE
417                ANSI_CURSOR_POSITION
418                ANSI_CURSOR_SHOW, 1, 1);
419
420         return ret;
421 }
422
423 /**
424  * eficonfig_volume_selected() - handler of volume selection
425  *
426  * @data:       pointer to the data of selected entry
427  * Return:      status code
428  */
429 static efi_status_t eficonfig_volume_selected(void *data)
430 {
431         struct eficonfig_volume_entry_data *info = data;
432
433         if (info) {
434                 info->file_info->current_volume = info->v;
435                 info->file_info->dp_volume = info->dp;
436         }
437
438         return EFI_SUCCESS;
439 }
440
441 /**
442  * eficonfig_create_device_path() - create device path
443  *
444  * @dp_volume:  pointer to the volume
445  * @current_path: pointer to the file path u16 string
446  * Return:
447  * device path or NULL. Caller must free the returned value
448  */
449 struct efi_device_path *eficonfig_create_device_path(struct efi_device_path *dp_volume,
450                                                      u16 *current_path)
451 {
452         char *p;
453         void *buf;
454         efi_uintn_t fp_size;
455         struct efi_device_path *dp;
456         struct efi_device_path_file_path *fp;
457
458         fp_size = sizeof(struct efi_device_path) + u16_strsize(current_path);
459         buf = calloc(1, fp_size + sizeof(END));
460         if (!buf)
461                 return NULL;
462
463         fp = buf;
464         fp->dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE,
465         fp->dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH,
466         fp->dp.length = (u16)fp_size;
467         u16_strcpy(fp->str, current_path);
468
469         p = buf;
470         p += fp_size;
471         *((struct efi_device_path *)p) = END;
472
473         dp = efi_dp_append(dp_volume, (struct efi_device_path *)buf);
474         free(buf);
475
476         return dp;
477 }
478
479 /**
480  * eficonfig_file_selected() - handler of file selection
481  *
482  * @data:       pointer to the data of selected entry
483  * Return:      status code
484  */
485 static efi_status_t eficonfig_file_selected(void *data)
486 {
487         u16 *tmp;
488         struct eficonfig_file_entry_data *info = data;
489
490         if (!info)
491                 return EFI_INVALID_PARAMETER;
492
493         if (!strcmp(info->file_name, "..\\")) {
494                 struct eficonfig_filepath_info *iter;
495                 struct list_head *pos, *n;
496                 int is_last;
497                 char *filepath;
498                 tmp = info->file_info->current_path;
499
500                 memset(info->file_info->current_path, 0, EFICONFIG_FILE_PATH_BUF_SIZE);
501                 filepath = calloc(1, EFICONFIG_FILE_PATH_MAX);
502                 if (!filepath)
503                         return EFI_OUT_OF_RESOURCES;
504
505                 list_for_each_safe(pos, n, &info->file_info->filepath_list) {
506                         iter = list_entry(pos, struct eficonfig_filepath_info, list);
507
508                         is_last = list_is_last(&iter->list, &info->file_info->filepath_list);
509                         if (is_last) {
510                                 list_del(&iter->list);
511                                 free(iter->name);
512                                 free(iter);
513                                 break;
514                         }
515                         strlcat(filepath, iter->name, EFICONFIG_FILE_PATH_MAX);
516                 }
517                 utf8_utf16_strcpy(&tmp, filepath);
518         } else {
519                 size_t new_len;
520                 struct eficonfig_filepath_info *filepath_info;
521
522                 new_len = u16_strlen(info->file_info->current_path) +
523                                      strlen(info->file_name);
524                 if (new_len >= EFICONFIG_FILE_PATH_MAX) {
525                         eficonfig_print_msg("File path is too long!");
526                         return EFI_INVALID_PARAMETER;
527                 }
528                 tmp = &info->file_info->current_path[u16_strlen(info->file_info->current_path)];
529                 utf8_utf16_strcpy(&tmp, info->file_name);
530
531                 filepath_info = calloc(1, sizeof(struct eficonfig_filepath_info));
532                 if (!filepath_info)
533                         return EFI_OUT_OF_RESOURCES;
534
535                 filepath_info->name = strdup(info->file_name);
536                 if (!filepath_info->name) {
537                         free(filepath_info);
538                         return EFI_OUT_OF_RESOURCES;
539                 }
540                 list_add_tail(&filepath_info->list, &info->file_info->filepath_list);
541
542                 if (!info->is_directory)
543                         info->file_info->file_selected = true;
544         }
545
546         return EFI_SUCCESS;
547 }
548
549 /**
550  * eficonfig_select_volume() - construct the volume selection menu
551  *
552  * @file_info:  pointer to the file selection structure
553  * Return:      status code
554  */
555 static efi_status_t eficonfig_select_volume(struct eficonfig_select_file_info *file_info)
556 {
557         u32 i;
558         efi_status_t ret;
559         efi_uintn_t count;
560         struct efimenu *efi_menu;
561         struct list_head *pos, *n;
562         struct efi_handler *handler;
563         struct eficonfig_entry *entry;
564         struct efi_device_path *device_path;
565         efi_handle_t *volume_handles = NULL;
566         struct efi_simple_file_system_protocol *v;
567
568         ret = efi_locate_handle_buffer_int(BY_PROTOCOL, &efi_simple_file_system_protocol_guid,
569                                            NULL, &count, (efi_handle_t **)&volume_handles);
570         if (ret != EFI_SUCCESS) {
571                 eficonfig_print_msg("No block device found!");
572                 return ret;
573         }
574
575         efi_menu = calloc(1, sizeof(struct efimenu));
576         if (!efi_menu)
577                 return EFI_OUT_OF_RESOURCES;
578
579         INIT_LIST_HEAD(&efi_menu->list);
580         for (i = 0; i < count; i++) {
581                 char *devname;
582                 struct efi_block_io *block_io;
583                 struct eficonfig_volume_entry_data *info;
584
585                 if (efi_menu->count >= EFICONFIG_ENTRY_NUM_MAX - 1)
586                         break;
587
588                 ret = efi_search_protocol(volume_handles[i],
589                                           &efi_simple_file_system_protocol_guid, &handler);
590                 if (ret != EFI_SUCCESS)
591                         continue;
592                 ret = efi_protocol_open(handler, (void **)&v, efi_root, NULL,
593                                         EFI_OPEN_PROTOCOL_GET_PROTOCOL);
594                 if (ret != EFI_SUCCESS)
595                         continue;
596
597                 ret = efi_search_protocol(volume_handles[i], &efi_guid_device_path, &handler);
598                 if (ret != EFI_SUCCESS)
599                         continue;
600                 ret = efi_protocol_open(handler, (void **)&device_path,
601                                         efi_root, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
602                 if (ret != EFI_SUCCESS)
603                         continue;
604
605                 ret = efi_search_protocol(volume_handles[i], &efi_block_io_guid, &handler);
606                 if (ret != EFI_SUCCESS)
607                         continue;
608                 ret = efi_protocol_open(handler, (void **)&block_io,
609                                         efi_root, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
610                 if (ret != EFI_SUCCESS)
611                         continue;
612
613                 info = calloc(1, sizeof(struct eficonfig_volume_entry_data));
614                 if (!info) {
615                         ret = EFI_OUT_OF_RESOURCES;
616                         goto out;
617                 }
618
619                 devname = calloc(1, BOOTMENU_DEVICE_NAME_MAX);
620                 if (!devname) {
621                         free(info);
622                         ret = EFI_OUT_OF_RESOURCES;
623                         goto out;
624                 }
625                 ret = efi_disk_get_device_name(volume_handles[i], devname,
626                                                BOOTMENU_DEVICE_NAME_MAX);
627                 if (ret != EFI_SUCCESS) {
628                         free(info);
629                         goto out;
630                 }
631
632                 info->v = v;
633                 info->dp = device_path;
634                 info->file_info = file_info;
635                 ret = eficonfig_append_menu_entry(efi_menu, devname, eficonfig_volume_selected,
636                                                   info);
637                 if (ret != EFI_SUCCESS) {
638                         free(info);
639                         goto out;
640                 }
641         }
642
643         ret = eficonfig_append_quit_entry(efi_menu);
644         if (ret != EFI_SUCCESS)
645                 goto out;
646
647         ret = eficonfig_process_common(efi_menu, "  ** Select Volume **");
648 out:
649         efi_free_pool(volume_handles);
650         list_for_each_safe(pos, n, &efi_menu->list) {
651                 entry = list_entry(pos, struct eficonfig_entry, list);
652                 free(entry->data);
653         }
654         eficonfig_destroy(efi_menu);
655
656         return ret;
657 }
658
659 /**
660  * sort_file() - sort the file name in ascii order
661  *
662  * @data1:      pointer to the file entry data
663  * @data2:      pointer to the file entry data
664  * Return:      -1 if the data1 file name is less than data2 file name,
665  *              0 if both file name match,
666  *              1 if the data1 file name is greater thant data2 file name.
667  */
668 static int sort_file(const void *arg1, const void *arg2)
669 {
670         const struct eficonfig_file_entry_data *data1, *data2;
671
672         data1 = *((const struct eficonfig_file_entry_data **)arg1);
673         data2 = *((const struct eficonfig_file_entry_data **)arg2);
674
675         return strcasecmp(data1->file_name, data2->file_name);
676 }
677
678 /**
679  * eficonfig_create_file_entry() - construct the file menu entry
680  *
681  * @efi_menu:   pointer to the efimenu structure
682  * @count:      number of the directory and file
683  * @tmp_infos:  pointer to the entry data array
684  * @f:          pointer to the file handle
685  * @buf:        pointer to the buffer to store the directory information
686  * @file_info:  pointer to the file selection structure
687  * Return:      status code
688  */
689 static efi_status_t
690 eficonfig_create_file_entry(struct efimenu *efi_menu, u32 count,
691                             struct eficonfig_file_entry_data **tmp_infos,
692                             struct efi_file_handle *f, struct efi_file_info *buf,
693                             struct eficonfig_select_file_info *file_info)
694 {
695         char *name, *p;
696         efi_uintn_t len;
697         efi_status_t ret;
698         u32 i, entry_num = 0;
699         struct eficonfig_file_entry_data *info;
700
701         EFI_CALL(f->setpos(f, 0));
702         /* Read directory and construct menu structure */
703         for (i = 0; i < count; i++) {
704                 if (entry_num >= EFICONFIG_ENTRY_NUM_MAX - 1)
705                         break;
706
707                 len = sizeof(struct efi_file_info) + EFICONFIG_FILE_PATH_BUF_SIZE;
708                 ret = EFI_CALL(f->read(f, &len, buf));
709                 if (ret != EFI_SUCCESS || len == 0)
710                         break;
711
712                 info = calloc(1, sizeof(struct eficonfig_file_entry_data));
713                 if (!info) {
714                         ret = EFI_OUT_OF_RESOURCES;
715                         goto out;
716                 }
717
718                 /* append '\\' at the end of directory name */
719                 name = calloc(1, utf16_utf8_strlen(buf->file_name) + 2);
720                 if (!name) {
721                         ret = EFI_OUT_OF_RESOURCES;
722                         free(info);
723                         goto out;
724                 }
725                 p = name;
726                 utf16_utf8_strcpy(&p, buf->file_name);
727                 if (buf->attribute & EFI_FILE_DIRECTORY) {
728                         /* filter out u'.' */
729                         if (!u16_strcmp(buf->file_name, u".")) {
730                                 free(info);
731                                 free(name);
732                                 continue;
733                         }
734                         name[u16_strlen(buf->file_name)] = '\\';
735                         info->is_directory = true;
736                 }
737
738                 info->file_name = name;
739                 info->file_info = file_info;
740                 tmp_infos[entry_num++] = info;
741         }
742
743         qsort(tmp_infos, entry_num, sizeof(*tmp_infos),
744               (int (*)(const void *, const void *))sort_file);
745
746         for (i = 0; i < entry_num; i++) {
747                 ret = eficonfig_append_menu_entry(efi_menu, tmp_infos[i]->file_name,
748                                                   eficonfig_file_selected, tmp_infos[i]);
749                 if (ret != EFI_SUCCESS)
750                         goto out;
751         }
752
753 out:
754         return ret;
755 }
756
757 /**
758  * eficonfig_show_file_selection() - construct the file selection menu
759  *
760  * @file_info:  pointer to the file selection structure
761  * @root:       pointer to the file handle
762  * Return:      status code
763  */
764 static efi_status_t eficonfig_show_file_selection(struct eficonfig_select_file_info *file_info,
765                                                   struct efi_file_handle *root)
766 {
767         u32 count = 0, i;
768         efi_uintn_t len;
769         efi_status_t ret;
770         struct efimenu *efi_menu;
771         struct efi_file_handle *f;
772         struct efi_file_info *buf;
773         struct eficonfig_file_entry_data **tmp_infos;
774
775         buf = calloc(1, sizeof(struct efi_file_info) + EFICONFIG_FILE_PATH_BUF_SIZE);
776         if (!buf)
777                 return EFI_OUT_OF_RESOURCES;
778
779         while (!file_info->file_selected) {
780                 efi_menu = calloc(1, sizeof(struct efimenu));
781                 if (!efi_menu) {
782                         ret = EFI_OUT_OF_RESOURCES;
783                         goto out;
784                 }
785                 INIT_LIST_HEAD(&efi_menu->list);
786
787                 ret = EFI_CALL(root->open(root, &f, file_info->current_path,
788                                           EFI_FILE_MODE_READ, 0));
789                 if (ret != EFI_SUCCESS) {
790                         eficonfig_print_msg("Reading volume failed!");
791                         free(efi_menu);
792                         ret = EFI_ABORTED;
793                         goto out;
794                 }
795
796                 /* Count the number of directory entries */
797                 for (;;) {
798                         len = sizeof(struct efi_file_info) + EFICONFIG_FILE_PATH_BUF_SIZE;
799                         ret = EFI_CALL(f->read(f, &len, buf));
800                         if (ret != EFI_SUCCESS || len == 0)
801                                 break;
802
803                         count++;
804                 }
805
806                 /* allocate array to sort the entry */
807                 tmp_infos = calloc(count, sizeof(*tmp_infos));
808                 if (!tmp_infos) {
809                         ret = EFI_OUT_OF_RESOURCES;
810                         goto err;
811                 }
812
813                 ret = eficonfig_create_file_entry(efi_menu, count, tmp_infos,
814                                                   f, buf, file_info);
815                 if (ret != EFI_SUCCESS)
816                         goto err;
817
818                 ret = eficonfig_append_quit_entry(efi_menu);
819                 if (ret != EFI_SUCCESS)
820                         goto err;
821
822                 ret = eficonfig_process_common(efi_menu, "  ** Select File **");
823 err:
824                 EFI_CALL(f->close(f));
825                 eficonfig_destroy(efi_menu);
826
827                 if (tmp_infos) {
828                         for (i = 0; i < count; i++)
829                                 free(tmp_infos[i]);
830                 }
831
832                 free(tmp_infos);
833
834                 if (ret != EFI_SUCCESS)
835                         break;
836         }
837
838 out:
839         free(buf);
840
841         return ret;
842 }
843
844 /**
845  * handle_user_input() - handle user input
846  *
847  * @buf:        pointer to the buffer
848  * @buf_size:   size of the buffer
849  * @cursor_col: cursor column for user input
850  * @msg:        pointer to the string to display
851  * Return:      status code
852  */
853 static efi_status_t handle_user_input(u16 *buf, int buf_size,
854                                       int cursor_col, char *msg)
855 {
856         u16 *tmp;
857         efi_status_t ret;
858
859         printf(ANSI_CLEAR_CONSOLE
860                ANSI_CURSOR_POSITION
861                "%s"
862                ANSI_CURSOR_POSITION
863                "  Press ENTER to complete, ESC/CTRL+C to quit",
864                0, 1, msg, 8, 1);
865
866         /* tmp is used to accept user cancel */
867         tmp = calloc(1, buf_size * sizeof(u16));
868         if (!tmp)
869                 return EFI_OUT_OF_RESOURCES;
870
871         ret = efi_console_get_u16_string(cin, tmp, buf_size, NULL, 4, cursor_col);
872         if (ret == EFI_SUCCESS)
873                 u16_strcpy(buf, tmp);
874
875         free(tmp);
876
877         /* to stay the parent menu */
878         ret = (ret == EFI_ABORTED) ? EFI_NOT_READY : ret;
879
880         return ret;
881 }
882
883 /**
884  * eficonfig_boot_add_enter_description() - handle user input for description
885  *
886  * @data:       pointer to the internal boot option structure
887  * Return:      status code
888  */
889 static efi_status_t eficonfig_boot_add_enter_description(void *data)
890 {
891         struct eficonfig_boot_option *bo = data;
892
893         return handle_user_input(bo->description, EFICONFIG_DESCRIPTION_MAX, 22,
894                                  "\n  ** Edit Description **\n"
895                                  "\n"
896                                  "  enter description: ");
897 }
898
899 /**
900  * eficonfig_boot_add_optional_data() - handle user input for optional data
901  *
902  * @data:       pointer to the internal boot option structure
903  * Return:      status code
904  */
905 static efi_status_t eficonfig_boot_add_optional_data(void *data)
906 {
907         struct eficonfig_boot_option *bo = data;
908
909         return handle_user_input(bo->optional_data, EFICONFIG_OPTIONAL_DATA_MAX, 24,
910                                  "\n  ** Edit Optional Data **\n"
911                                  "\n"
912                                  "  enter optional data:");
913 }
914
915 /**
916  * eficonfig_boot_edit_save() - handler to save the boot option
917  *
918  * @data:       pointer to the internal boot option structure
919  * Return:      status code
920  */
921 static efi_status_t eficonfig_boot_edit_save(void *data)
922 {
923         struct eficonfig_boot_option *bo = data;
924
925         if (u16_strlen(bo->description) == 0) {
926                 eficonfig_print_msg("Boot Description is empty!");
927                 bo->edit_completed = false;
928                 return EFI_NOT_READY;
929         }
930         if (u16_strlen(bo->file_info.current_path) == 0) {
931                 eficonfig_print_msg("File is not selected!");
932                 bo->edit_completed = false;
933                 return EFI_NOT_READY;
934         }
935
936         bo->edit_completed = true;
937
938         return EFI_SUCCESS;
939 }
940
941 /**
942  * eficonfig_process_clear_file_selection() - callback function for "Clear" entry
943  *
944  * @data:       pointer to the data
945  * Return:      status code
946  */
947 efi_status_t eficonfig_process_clear_file_selection(void *data)
948 {
949         struct eficonfig_select_file_info *file_info = data;
950
951         /* clear the existing file information */
952         file_info->current_volume = NULL;
953         file_info->current_path[0] = u'\0';
954         file_info->dp_volume = NULL;
955
956         return EFI_ABORTED;
957 }
958
959 static struct eficonfig_item select_file_menu_items[] = {
960         {"Select File", eficonfig_process_select_file},
961         {"Clear", eficonfig_process_clear_file_selection},
962         {"Quit", eficonfig_process_quit},
963 };
964
965 /**
966  * eficonfig_process_show_file_option() - display select file option
967  *
968  * @file_info:  pointer to the file information structure
969  * Return:      status code
970  */
971 efi_status_t eficonfig_process_show_file_option(void *data)
972 {
973         efi_status_t ret;
974         struct efimenu *efi_menu;
975
976         select_file_menu_items[0].data = data;
977         select_file_menu_items[1].data = data;
978         efi_menu = eficonfig_create_fixed_menu(select_file_menu_items,
979                                                ARRAY_SIZE(select_file_menu_items));
980         if (!efi_menu)
981                 return EFI_OUT_OF_RESOURCES;
982
983         ret = eficonfig_process_common(efi_menu, "  ** Update File **");
984         if (ret != EFI_SUCCESS) /* User selects "Clear" or "Quit" */
985                 ret = EFI_NOT_READY;
986
987         eficonfig_destroy(efi_menu);
988
989         return ret;
990 }
991
992 /**
993  * eficonfig_process_select_file() - handle user file selection
994  *
995  * @data:       pointer to the data
996  * Return:      status code
997  */
998 efi_status_t eficonfig_process_select_file(void *data)
999 {
1000         size_t len;
1001         efi_status_t ret;
1002         struct list_head *pos, *n;
1003         struct efi_file_handle *root;
1004         struct eficonfig_filepath_info *item;
1005         struct eficonfig_select_file_info *tmp = NULL;
1006         struct eficonfig_select_file_info *file_info = data;
1007
1008         tmp = calloc(1, sizeof(struct eficonfig_select_file_info));
1009         if (!tmp)
1010                 return EFI_OUT_OF_RESOURCES;
1011
1012         tmp->current_path = calloc(1, EFICONFIG_FILE_PATH_BUF_SIZE);
1013         if (!tmp->current_path) {
1014                 free(tmp);
1015                 return EFI_OUT_OF_RESOURCES;
1016         }
1017         INIT_LIST_HEAD(&tmp->filepath_list);
1018
1019         while (!tmp->file_selected) {
1020                 tmp->current_volume = NULL;
1021                 memset(tmp->current_path, 0, EFICONFIG_FILE_PATH_BUF_SIZE);
1022
1023                 ret = eficonfig_select_volume(tmp);
1024                 if (ret != EFI_SUCCESS)
1025                         goto out;
1026
1027                 if (!tmp->current_volume)
1028                         return EFI_INVALID_PARAMETER;
1029
1030                 ret = EFI_CALL(tmp->current_volume->open_volume(tmp->current_volume, &root));
1031                 if (ret != EFI_SUCCESS)
1032                         goto out;
1033
1034                 ret = eficonfig_show_file_selection(tmp, root);
1035                 if (ret == EFI_ABORTED)
1036                         continue;
1037                 if (ret != EFI_SUCCESS)
1038                         goto out;
1039         }
1040
1041 out:
1042         if (ret == EFI_SUCCESS) {
1043                 len = u16_strlen(tmp->current_path);
1044                 len = (len >= EFICONFIG_FILE_PATH_MAX) ? (EFICONFIG_FILE_PATH_MAX - 1) : len;
1045                 memcpy(file_info->current_path, tmp->current_path, len * sizeof(u16));
1046                 file_info->current_path[len] = u'\0';
1047                 file_info->current_volume = tmp->current_volume;
1048                 file_info->dp_volume = tmp->dp_volume;
1049         }
1050
1051         list_for_each_safe(pos, n, &tmp->filepath_list) {
1052                 item = list_entry(pos, struct eficonfig_filepath_info, list);
1053                 list_del(&item->list);
1054                 free(item->name);
1055                 free(item);
1056         }
1057         free(tmp->current_path);
1058         free(tmp);
1059
1060         /* to stay the parent menu */
1061         ret = (ret == EFI_ABORTED) ? EFI_NOT_READY : ret;
1062
1063         return ret;
1064 }
1065
1066 /**
1067  * eficonfig_get_unused_bootoption() - get unused "Boot####" index
1068  *
1069  * @buf:        pointer to the buffer to store boot option variable name
1070  * @buf_size:   buffer size
1071  * @index:      pointer to store the index in the BootOrder variable
1072  * Return:      status code
1073  */
1074 efi_status_t eficonfig_get_unused_bootoption(u16 *buf, efi_uintn_t buf_size,
1075                                              unsigned int *index)
1076 {
1077         u32 i;
1078         efi_status_t ret;
1079         efi_uintn_t size;
1080
1081         if (buf_size < u16_strsize(u"Boot####"))
1082                 return EFI_BUFFER_TOO_SMALL;
1083
1084         for (i = 0; i <= 0xFFFF; i++) {
1085                 size = 0;
1086                 efi_create_indexed_name(buf, buf_size, "Boot", i);
1087                 ret = efi_get_variable_int(buf, &efi_global_variable_guid,
1088                                            NULL, &size, NULL, NULL);
1089                 if (ret == EFI_BUFFER_TOO_SMALL)
1090                         continue;
1091                 else
1092                         break;
1093         }
1094
1095         if (i > 0xFFFF)
1096                 return EFI_OUT_OF_RESOURCES;
1097
1098         *index = i;
1099
1100         return EFI_SUCCESS;
1101 }
1102
1103 /**
1104  * eficonfig_set_boot_option() - set boot option
1105  *
1106  * @varname:            pointer to variable name
1107  * @dp:                 pointer to device path
1108  * @label:              pointer to label string
1109  * @optional_data:      pointer to optional data
1110  * Return:              status code
1111  */
1112 static efi_status_t eficonfig_set_boot_option(u16 *varname, struct efi_device_path *dp,
1113                                               efi_uintn_t dp_size, u16 *label, char *optional_data)
1114 {
1115         void *p = NULL;
1116         efi_status_t ret;
1117         efi_uintn_t size;
1118         struct efi_load_option lo;
1119
1120         lo.file_path = dp;
1121         lo.file_path_length = dp_size;
1122         lo.attributes = LOAD_OPTION_ACTIVE;
1123         lo.optional_data = optional_data;
1124         lo.label = label;
1125
1126         size = efi_serialize_load_option(&lo, (u8 **)&p);
1127         if (!size)
1128                 return EFI_INVALID_PARAMETER;
1129
1130         ret = efi_set_variable_int(varname, &efi_global_variable_guid,
1131                                    EFI_VARIABLE_NON_VOLATILE |
1132                                    EFI_VARIABLE_BOOTSERVICE_ACCESS |
1133                                    EFI_VARIABLE_RUNTIME_ACCESS,
1134                                    size, p, false);
1135         free(p);
1136
1137         return ret;
1138 }
1139
1140 /**
1141  * eficonfig_append_bootorder() - append new boot option in BootOrder variable
1142  *
1143  * @index:      "Boot####" index to append to BootOrder variable
1144  * Return:      status code
1145  */
1146 efi_status_t eficonfig_append_bootorder(u16 index)
1147 {
1148         u16 *bootorder;
1149         efi_status_t ret;
1150         u16 *new_bootorder = NULL;
1151         efi_uintn_t last, size, new_size;
1152
1153         /* append new boot option */
1154         bootorder = efi_get_var(u"BootOrder", &efi_global_variable_guid, &size);
1155         last = size / sizeof(u16);
1156         new_size = size + sizeof(u16);
1157         new_bootorder = calloc(1, new_size);
1158         if (!new_bootorder) {
1159                 ret = EFI_OUT_OF_RESOURCES;
1160                 goto out;
1161         }
1162         memcpy(new_bootorder, bootorder, size);
1163         new_bootorder[last] = index;
1164
1165         ret = efi_set_variable_int(u"BootOrder", &efi_global_variable_guid,
1166                                    EFI_VARIABLE_NON_VOLATILE |
1167                                    EFI_VARIABLE_BOOTSERVICE_ACCESS |
1168                                    EFI_VARIABLE_RUNTIME_ACCESS,
1169                                    new_size, new_bootorder, false);
1170         if (ret != EFI_SUCCESS)
1171                 goto out;
1172
1173 out:
1174         free(bootorder);
1175         free(new_bootorder);
1176
1177         return ret;
1178 }
1179
1180 /**
1181  * create_boot_option_entry() - create boot option entry
1182  *
1183  * @efi_menu:   pointer to the efimenu structure
1184  * @title:      pointer to the entry title
1185  * @val:        pointer to boot option label
1186  * @func:       callback of each entry
1187  * @data:       pointer to the data to be passed to each entry callback
1188  * Return:      status code
1189  */
1190 static efi_status_t create_boot_option_entry(struct efimenu *efi_menu, char *title, u16 *val,
1191                                              eficonfig_entry_func func, void *data)
1192 {
1193         u32 len;
1194         char *p, *buf;
1195
1196         len = strlen(title) + 1;
1197         if (val)
1198                 len += utf16_utf8_strlen(val);
1199         buf = calloc(1, len);
1200         if (!buf)
1201                 return EFI_OUT_OF_RESOURCES;
1202
1203         strcpy(buf, title);
1204         if (val) {
1205                 p = buf + strlen(title);
1206                 utf16_utf8_strcpy(&p, val);
1207         }
1208
1209         return eficonfig_append_menu_entry(efi_menu, buf, func, data);
1210 }
1211
1212 /**
1213  * prepare_file_selection_entry() - prepare file selection entry
1214  *
1215  * @efi_menu:   pointer to the efimenu structure
1216  * @title:      pointer to the title string
1217  * @file_info:  pointer to the file info
1218  * Return:      status code
1219  */
1220 static efi_status_t prepare_file_selection_entry(struct efimenu *efi_menu, char *title,
1221                                                  struct eficonfig_select_file_info *file_info)
1222 {
1223         u32 len;
1224         efi_status_t ret;
1225         u16 *file_name = NULL, *p;
1226         efi_handle_t handle;
1227         char *devname;
1228
1229         devname = calloc(1, EFICONFIG_VOLUME_PATH_MAX + 1);
1230         if (!devname)
1231                 return EFI_OUT_OF_RESOURCES;
1232
1233         /* get the device name only when the user already selected the file path */
1234         handle = efi_dp_find_obj(file_info->dp_volume, NULL, NULL);
1235         if (handle) {
1236                 ret = efi_disk_get_device_name(handle, devname, EFICONFIG_VOLUME_PATH_MAX);
1237                 if (ret != EFI_SUCCESS)
1238                         goto out;
1239         }
1240
1241         /*
1242          * If the preconfigured volume does not exist in the system, display the text
1243          * converted volume device path instead of U-Boot friendly name(e.g. "usb 0:1").
1244          */
1245         if (!handle && file_info->dp_volume) {
1246                 u16 *dp_str;
1247                 char *q = devname;
1248
1249                 dp_str = efi_dp_str(file_info->dp_volume);
1250                 if (dp_str)
1251                         utf16_utf8_strncpy(&q, dp_str, EFICONFIG_VOLUME_PATH_MAX);
1252
1253                 efi_free_pool(dp_str);
1254         }
1255
1256         /* append u'/' to devname, it is just for display purpose. */
1257         if (file_info->current_path[0] != u'\0' && file_info->current_path[0] != u'/')
1258                 strlcat(devname, "/", EFICONFIG_VOLUME_PATH_MAX + 1);
1259
1260         len = strlen(devname);
1261         len += utf16_utf8_strlen(file_info->current_path) + 1;
1262         file_name = calloc(1, len * sizeof(u16));
1263         if (!file_name) {
1264                 ret = EFI_OUT_OF_RESOURCES;
1265                 goto out;
1266         }
1267
1268         p = file_name;
1269         utf8_utf16_strcpy(&p, devname);
1270         u16_strlcat(file_name, file_info->current_path, len);
1271         ret = create_boot_option_entry(efi_menu, title, file_name,
1272                                        eficonfig_process_show_file_option, file_info);
1273 out:
1274         free(devname);
1275         free(file_name);
1276
1277         return ret;
1278 }
1279
1280 /**
1281  * eficonfig_show_boot_option() - prepare menu entry for editing boot option
1282  *
1283  * Construct the structures to create edit boot option menu
1284  *
1285  * @bo:         pointer to the boot option
1286  * @header_str: pointer to the header string
1287  * Return:      status code
1288  */
1289 static efi_status_t eficonfig_show_boot_option(struct eficonfig_boot_option *bo,
1290                                                char *header_str)
1291 {
1292         efi_status_t ret;
1293         struct efimenu *efi_menu;
1294
1295         efi_menu = calloc(1, sizeof(struct efimenu));
1296         if (!efi_menu)
1297                 return EFI_OUT_OF_RESOURCES;
1298
1299         INIT_LIST_HEAD(&efi_menu->list);
1300
1301         ret = create_boot_option_entry(efi_menu, "Description: ", bo->description,
1302                                        eficonfig_boot_add_enter_description, bo);
1303         if (ret != EFI_SUCCESS)
1304                 goto out;
1305
1306         ret = prepare_file_selection_entry(efi_menu, "File: ", &bo->file_info);
1307         if (ret != EFI_SUCCESS)
1308                 goto out;
1309
1310         ret = prepare_file_selection_entry(efi_menu, "Initrd File: ", &bo->initrd_info);
1311         if (ret != EFI_SUCCESS)
1312                 goto out;
1313
1314         ret = create_boot_option_entry(efi_menu, "Optional Data: ", bo->optional_data,
1315                                        eficonfig_boot_add_optional_data, bo);
1316         if (ret != EFI_SUCCESS)
1317                 goto out;
1318
1319         ret = create_boot_option_entry(efi_menu, "Save", NULL,
1320                                        eficonfig_boot_edit_save, bo);
1321         if (ret != EFI_SUCCESS)
1322                 goto out;
1323
1324         ret = create_boot_option_entry(efi_menu, "Quit", NULL,
1325                                        eficonfig_process_quit, NULL);
1326         if (ret != EFI_SUCCESS)
1327                 goto out;
1328
1329         ret = eficonfig_process_common(efi_menu, header_str);
1330 out:
1331         eficonfig_destroy(efi_menu);
1332
1333         return ret;
1334 }
1335
1336 /**
1337  * fill_file_info() - fill the file info from efi_device_path structure
1338  *
1339  * @dp:         pointer to the device path
1340  * @file_info:  pointer to the file info structure
1341  * @device_dp:  pointer to the volume device path
1342  */
1343 static void fill_file_info(struct efi_device_path *dp,
1344                            struct eficonfig_select_file_info *file_info,
1345                            struct efi_device_path *device_dp)
1346 {
1347         u16 *file_str, *p;
1348         struct efi_device_path *file_dp = NULL;
1349
1350         efi_dp_split_file_path(dp, &device_dp, &file_dp);
1351         file_info->dp_volume = device_dp;
1352
1353         if (file_dp) {
1354                 file_str = efi_dp_str(file_dp);
1355                 /*
1356                  * efi_convert_device_path_to_text() automatically adds u'/' at the
1357                  * beginning of file name, remove u'/' before copying to current_path
1358                  */
1359                 p = file_str;
1360                 if (p[0] == u'/')
1361                         p++;
1362
1363                 u16_strcpy(file_info->current_path, p);
1364                 efi_free_pool(file_dp);
1365                 efi_free_pool(file_str);
1366         }
1367 }
1368
1369 /**
1370  * eficonfig_edit_boot_option() - prepare boot option structure for editing
1371  *
1372  * Construct the boot option structure and copy the existing value
1373  *
1374  * @varname:            pointer to the UEFI variable name
1375  * @bo:                 pointer to the boot option
1376  * @load_option:        pointer to the load option
1377  * @load_option_size:   size of the load option
1378  * @header_str:         pointer to the header string
1379  * Return       :       status code
1380  */
1381 static efi_status_t eficonfig_edit_boot_option(u16 *varname, struct eficonfig_boot_option *bo,
1382                                                void *load_option, efi_uintn_t load_option_size,
1383                                                char *header_str)
1384 {
1385         size_t len;
1386         efi_status_t ret;
1387         char *tmp = NULL, *p;
1388         struct efi_load_option lo = {0};
1389         efi_uintn_t final_dp_size;
1390         struct efi_device_path *dp = NULL;
1391         efi_uintn_t size = load_option_size;
1392         struct efi_device_path *final_dp = NULL;
1393         struct efi_device_path *device_dp = NULL;
1394         struct efi_device_path *initrd_dp = NULL;
1395         struct efi_device_path *initrd_device_dp = NULL;
1396
1397         const struct efi_initrd_dp id_dp = {
1398                 .vendor = {
1399                         {
1400                         DEVICE_PATH_TYPE_MEDIA_DEVICE,
1401                         DEVICE_PATH_SUB_TYPE_VENDOR_PATH,
1402                         sizeof(id_dp.vendor),
1403                         },
1404                         EFI_INITRD_MEDIA_GUID,
1405                 },
1406                 .end = {
1407                         DEVICE_PATH_TYPE_END,
1408                         DEVICE_PATH_SUB_TYPE_END,
1409                         sizeof(id_dp.end),
1410                 }
1411         };
1412
1413         bo->file_info.current_path = calloc(1, EFICONFIG_FILE_PATH_BUF_SIZE);
1414         if (!bo->file_info.current_path) {
1415                 ret =  EFI_OUT_OF_RESOURCES;
1416                 goto out;
1417         }
1418
1419         bo->initrd_info.current_path = calloc(1, EFICONFIG_FILE_PATH_BUF_SIZE);
1420         if (!bo->file_info.current_path) {
1421                 ret =  EFI_OUT_OF_RESOURCES;
1422                 goto out;
1423         }
1424
1425         bo->description = calloc(1, EFICONFIG_DESCRIPTION_MAX * sizeof(u16));
1426         if (!bo->description) {
1427                 ret =  EFI_OUT_OF_RESOURCES;
1428                 goto out;
1429         }
1430
1431         bo->optional_data = calloc(1, EFICONFIG_OPTIONAL_DATA_MAX * sizeof(u16));
1432         if (!bo->optional_data) {
1433                 ret =  EFI_OUT_OF_RESOURCES;
1434                 goto out;
1435         }
1436
1437         /* copy the preset value */
1438         if (load_option) {
1439                 ret = efi_deserialize_load_option(&lo, load_option, &size);
1440                 if (ret != EFI_SUCCESS)
1441                         goto out;
1442
1443                 if (!lo.label) {
1444                         ret = EFI_INVALID_PARAMETER;
1445                         goto out;
1446                 }
1447                 /* truncate the long label string */
1448                 if (u16_strlen(lo.label) >= EFICONFIG_DESCRIPTION_MAX)
1449                         lo.label[EFICONFIG_DESCRIPTION_MAX - 1] = u'\0';
1450
1451                 u16_strcpy(bo->description, lo.label);
1452
1453                 /* EFI image file path is a first instance */
1454                 if (lo.file_path)
1455                         fill_file_info(lo.file_path, &bo->file_info, device_dp);
1456
1457                 /* Initrd file path(optional) is placed at second instance. */
1458                 initrd_dp = efi_dp_from_lo(&lo, &efi_lf2_initrd_guid);
1459                 if (initrd_dp) {
1460                         fill_file_info(initrd_dp, &bo->initrd_info, initrd_device_dp);
1461                         efi_free_pool(initrd_dp);
1462                 }
1463
1464                 if (size > 0)
1465                         memcpy(bo->optional_data, lo.optional_data, size);
1466         }
1467
1468         while (1) {
1469                 ret = eficonfig_show_boot_option(bo, header_str);
1470                 if (ret == EFI_SUCCESS && bo->edit_completed)
1471                         break;
1472                 if (ret == EFI_NOT_READY)
1473                         continue;
1474                 if (ret != EFI_SUCCESS)
1475                         goto out;
1476         }
1477
1478         if (bo->initrd_info.dp_volume) {
1479                 dp = eficonfig_create_device_path(bo->initrd_info.dp_volume,
1480                                                  bo->initrd_info.current_path);
1481                 if (!dp) {
1482                         ret = EFI_OUT_OF_RESOURCES;
1483                         goto out;
1484                 }
1485                 initrd_dp = efi_dp_append((const struct efi_device_path *)&id_dp, dp);
1486                 efi_free_pool(dp);
1487         }
1488
1489         dp = eficonfig_create_device_path(bo->file_info.dp_volume, bo->file_info.current_path);
1490         if (!dp) {
1491                 ret = EFI_OUT_OF_RESOURCES;
1492                 goto out;
1493         }
1494         final_dp_size = efi_dp_size(dp) + sizeof(END);
1495         if (initrd_dp) {
1496                 final_dp = efi_dp_concat(dp, initrd_dp);
1497                 final_dp_size += efi_dp_size(initrd_dp) + sizeof(END);
1498         } else {
1499                 final_dp = efi_dp_dup(dp);
1500         }
1501         efi_free_pool(dp);
1502
1503         if (!final_dp)
1504                 goto out;
1505
1506         if (utf16_utf8_strlen(bo->optional_data)) {
1507                 len = utf16_utf8_strlen(bo->optional_data) + 1;
1508                 tmp = calloc(1, len);
1509                 if (!tmp)
1510                         goto out;
1511                 p = tmp;
1512                 utf16_utf8_strncpy(&p, bo->optional_data, u16_strlen(bo->optional_data));
1513         }
1514
1515         ret = eficonfig_set_boot_option(varname, final_dp, final_dp_size, bo->description, tmp);
1516 out:
1517         free(tmp);
1518         free(bo->optional_data);
1519         free(bo->description);
1520         free(bo->file_info.current_path);
1521         free(bo->initrd_info.current_path);
1522         efi_free_pool(device_dp);
1523         efi_free_pool(initrd_device_dp);
1524         efi_free_pool(initrd_dp);
1525         efi_free_pool(final_dp);
1526
1527         return ret;
1528 }
1529
1530 /**
1531  * eficonfig_process_add_boot_option() - handler to add boot option
1532  *
1533  * @data:       pointer to the data for each entry
1534  * Return:      status code
1535  */
1536 static efi_status_t eficonfig_process_add_boot_option(void *data)
1537 {
1538         u16 varname[9];
1539         efi_status_t ret;
1540         struct eficonfig_boot_option *bo = NULL;
1541
1542         bo = calloc(1, sizeof(struct eficonfig_boot_option));
1543         if (!bo)
1544                 return EFI_OUT_OF_RESOURCES;
1545
1546         ret = eficonfig_get_unused_bootoption(varname, sizeof(varname), &bo->boot_index);
1547         if (ret != EFI_SUCCESS)
1548                 return ret;
1549
1550         ret = eficonfig_edit_boot_option(varname, bo, NULL, 0,  "  ** Add Boot Option ** ");
1551         if (ret != EFI_SUCCESS)
1552                 goto out;
1553
1554         ret = eficonfig_append_bootorder((u16)bo->boot_index);
1555         if (ret != EFI_SUCCESS)
1556                 goto out;
1557
1558 out:
1559         free(bo);
1560
1561         /* to stay the parent menu */
1562         ret = (ret == EFI_ABORTED) ? EFI_SUCCESS : ret;
1563
1564         return ret;
1565 }
1566
1567 /**
1568  * eficonfig_process_boot_selected() - handler to select boot option entry
1569  *
1570  * @data:       pointer to the data for each entry
1571  * Return:      status code
1572  */
1573 static efi_status_t eficonfig_process_boot_selected(void *data)
1574 {
1575         struct eficonfig_boot_selection_data *info = data;
1576
1577         if (info)
1578                 *info->selected = info->boot_index;
1579
1580         return EFI_SUCCESS;
1581 }
1582
1583 /**
1584  * search_bootorder() - search the boot option index in BootOrder
1585  *
1586  * @bootorder:  pointer to the BootOrder variable
1587  * @num:        number of BootOrder entry
1588  * @target:     target boot option index to search
1589  * @index:      pointer to store the index of BootOrder variable
1590  * Return:      true if exists, false otherwise
1591  */
1592 static bool search_bootorder(u16 *bootorder, efi_uintn_t num, u32 target, u32 *index)
1593 {
1594         u32 i;
1595
1596         for (i = 0; i < num; i++) {
1597                 if (target == bootorder[i]) {
1598                         if (index)
1599                                 *index = i;
1600
1601                         return true;
1602                 }
1603         }
1604
1605         return false;
1606 }
1607
1608 /**
1609  * eficonfig_add_boot_selection_entry() - add boot option menu entry
1610  *
1611  * @efi_menu:   pointer to store the efimenu structure
1612  * @boot_index: boot option index to be added
1613  * @selected:   pointer to store the selected boot option index
1614  * Return:      status code
1615  */
1616 static efi_status_t eficonfig_add_boot_selection_entry(struct efimenu *efi_menu,
1617                                                        unsigned int boot_index,
1618                                                        unsigned int *selected)
1619 {
1620         char *buf, *p;
1621         efi_status_t ret;
1622         efi_uintn_t size;
1623         void *load_option;
1624         struct efi_load_option lo;
1625         u16 varname[] = u"Boot####";
1626         struct eficonfig_boot_selection_data *info;
1627
1628         efi_create_indexed_name(varname, sizeof(varname), "Boot", boot_index);
1629         load_option = efi_get_var(varname, &efi_global_variable_guid, &size);
1630         if (!load_option)
1631                 return EFI_SUCCESS;
1632
1633         ret = efi_deserialize_load_option(&lo, load_option, &size);
1634         if (ret != EFI_SUCCESS) {
1635                 log_warning("Invalid load option for %ls\n", varname);
1636                 free(load_option);
1637                 return ret;
1638         }
1639
1640         if (size >= sizeof(efi_guid_t) &&
1641             !guidcmp(lo.optional_data, &efi_guid_bootmenu_auto_generated)) {
1642                 /*
1643                  * auto generated entry has GUID in optional_data,
1644                  * skip auto generated entry because it will be generated
1645                  * again even if it is edited or deleted.
1646                  */
1647                 free(load_option);
1648                 return EFI_SUCCESS;
1649         }
1650
1651         info = calloc(1, sizeof(struct eficonfig_boot_selection_data));
1652         if (!info) {
1653                 free(load_option);
1654                 return EFI_OUT_OF_RESOURCES;
1655         }
1656
1657         buf = calloc(1, utf16_utf8_strlen(lo.label) + 1);
1658         if (!buf) {
1659                 free(load_option);
1660                 free(info);
1661                 return EFI_OUT_OF_RESOURCES;
1662         }
1663         p = buf;
1664         utf16_utf8_strcpy(&p, lo.label);
1665         info->boot_index = boot_index;
1666         info->selected = selected;
1667         ret = eficonfig_append_menu_entry(efi_menu, buf, eficonfig_process_boot_selected, info);
1668         if (ret != EFI_SUCCESS) {
1669                 free(load_option);
1670                 free(info);
1671                 return ret;
1672         }
1673         free(load_option);
1674
1675         return EFI_SUCCESS;
1676 }
1677
1678 /**
1679  * eficonfig_show_boot_selection() - construct boot option menu entry
1680  *
1681  * @selected:   pointer to store the selected boot option index
1682  * Return:      status code
1683  */
1684 static efi_status_t eficonfig_show_boot_selection(unsigned int *selected)
1685 {
1686         u32 i;
1687         u16 *bootorder;
1688         efi_status_t ret;
1689         u16 *var_name16 = NULL;
1690         efi_uintn_t num, size, buf_size;
1691         struct efimenu *efi_menu;
1692         struct list_head *pos, *n;
1693         struct eficonfig_entry *entry;
1694
1695         efi_menu = calloc(1, sizeof(struct efimenu));
1696         if (!efi_menu)
1697                 return EFI_OUT_OF_RESOURCES;
1698
1699         bootorder = efi_get_var(u"BootOrder", &efi_global_variable_guid, &size);
1700
1701         INIT_LIST_HEAD(&efi_menu->list);
1702         num = size / sizeof(u16);
1703         /* list the load option in the order of BootOrder variable */
1704         for (i = 0; i < num; i++) {
1705                 ret = eficonfig_add_boot_selection_entry(efi_menu, bootorder[i], selected);
1706                 if (ret != EFI_SUCCESS)
1707                         goto out;
1708
1709                 if (efi_menu->count >= EFICONFIG_ENTRY_NUM_MAX - 1)
1710                         break;
1711         }
1712
1713         /* list the remaining load option not included in the BootOrder */
1714         buf_size = 128;
1715         var_name16 = malloc(buf_size);
1716         if (!var_name16)
1717                 return EFI_OUT_OF_RESOURCES;
1718
1719         var_name16[0] = 0;
1720         for (;;) {
1721                 int index;
1722                 efi_guid_t guid;
1723
1724                 ret = efi_next_variable_name(&buf_size, &var_name16, &guid);
1725                 if (ret == EFI_NOT_FOUND)
1726                         break;
1727                 if (ret != EFI_SUCCESS)
1728                         goto out;
1729
1730                 if (efi_varname_is_load_option(var_name16, &index)) {
1731                         /* If the index is included in the BootOrder, skip it */
1732                         if (search_bootorder(bootorder, num, index, NULL))
1733                                 continue;
1734
1735                         ret = eficonfig_add_boot_selection_entry(efi_menu, index, selected);
1736                         if (ret != EFI_SUCCESS)
1737                                 goto out;
1738                 }
1739
1740                 if (efi_menu->count >= EFICONFIG_ENTRY_NUM_MAX - 1)
1741                         break;
1742         }
1743
1744         ret = eficonfig_append_quit_entry(efi_menu);
1745         if (ret != EFI_SUCCESS)
1746                 goto out;
1747
1748         ret = eficonfig_process_common(efi_menu, "  ** Select Boot Option **");
1749 out:
1750         list_for_each_safe(pos, n, &efi_menu->list) {
1751                 entry = list_entry(pos, struct eficonfig_entry, list);
1752                 free(entry->data);
1753         }
1754         eficonfig_destroy(efi_menu);
1755
1756         free(var_name16);
1757
1758         return ret;
1759 }
1760
1761 /**
1762  * eficonfig_process_edit_boot_option() - handler to edit boot option
1763  *
1764  * @data:       pointer to the data for each entry
1765  * Return:      status code
1766  */
1767 static efi_status_t eficonfig_process_edit_boot_option(void *data)
1768 {
1769         efi_status_t ret;
1770         efi_uintn_t size;
1771         struct eficonfig_boot_option *bo = NULL;
1772
1773         while (1) {
1774                 unsigned int selected;
1775                 void *load_option;
1776                 u16 varname[] = u"Boot####";
1777
1778                 ret = eficonfig_show_boot_selection(&selected);
1779                 if (ret != EFI_SUCCESS)
1780                         break;
1781
1782                 bo = calloc(1, sizeof(struct eficonfig_boot_option));
1783                 if (!bo) {
1784                         ret = EFI_OUT_OF_RESOURCES;
1785                         goto out;
1786                 }
1787
1788                 bo->boot_index = selected;
1789                 efi_create_indexed_name(varname, sizeof(varname), "Boot", selected);
1790                 load_option = efi_get_var(varname, &efi_global_variable_guid, &size);
1791                 if (!load_option) {
1792                         free(bo);
1793                         ret = EFI_NOT_FOUND;
1794                         goto out;
1795                 }
1796
1797                 ret = eficonfig_edit_boot_option(varname, bo, load_option, size,
1798                                                  "  ** Edit Boot Option ** ");
1799
1800                 free(load_option);
1801                 free(bo);
1802                 if (ret != EFI_SUCCESS && ret != EFI_ABORTED)
1803                         break;
1804         }
1805 out:
1806         /* to stay the parent menu */
1807         ret = (ret == EFI_ABORTED) ? EFI_NOT_READY : ret;
1808
1809         return ret;
1810 }
1811
1812 /**
1813  * eficonfig_display_change_boot_order() - display the BootOrder list
1814  *
1815  * @efi_menu:   pointer to the efimenu structure
1816  * Return:      status code
1817  */
1818 static void eficonfig_display_change_boot_order(struct efimenu *efi_menu)
1819 {
1820         bool reverse;
1821         struct list_head *pos, *n;
1822         struct eficonfig_entry *entry;
1823
1824         printf(ANSI_CLEAR_CONSOLE ANSI_CURSOR_POSITION
1825                "\n  ** Change Boot Order **\n"
1826                ANSI_CURSOR_POSITION
1827                "  Press UP/DOWN to move, +/- to change order"
1828                ANSI_CURSOR_POSITION
1829                "  Press SPACE to activate or deactivate the entry"
1830                ANSI_CURSOR_POSITION
1831                "  Select [Save] to complete, ESC/CTRL+C to quit"
1832                ANSI_CURSOR_POSITION ANSI_CLEAR_LINE,
1833                1, 1, efi_menu->count + 5, 1, efi_menu->count + 6, 1,
1834                efi_menu->count + 7, 1,  efi_menu->count + 8, 1);
1835
1836         /* draw boot option list */
1837         list_for_each_safe(pos, n, &efi_menu->list) {
1838                 entry = list_entry(pos, struct eficonfig_entry, list);
1839                 reverse = (entry->num == efi_menu->active);
1840
1841                 printf(ANSI_CURSOR_POSITION, entry->num + 4, 7);
1842
1843                 if (reverse)
1844                         puts(ANSI_COLOR_REVERSE);
1845
1846                 if (entry->num < efi_menu->count - 2) {
1847                         if (((struct eficonfig_boot_order_data *)entry->data)->active)
1848                                 printf("[*]  ");
1849                         else
1850                                 printf("[ ]  ");
1851                 }
1852
1853                 printf("%s", entry->title);
1854
1855                 if (reverse)
1856                         puts(ANSI_COLOR_RESET);
1857         }
1858 }
1859
1860 /**
1861  * eficonfig_choice_change_boot_order() - handle the BootOrder update
1862  *
1863  * @efi_menu:   pointer to the efimenu structure
1864  * Return:      status code
1865  */
1866 static efi_status_t eficonfig_choice_change_boot_order(struct efimenu *efi_menu)
1867 {
1868         struct cli_ch_state s_cch, *cch = &s_cch;
1869         struct list_head *pos, *n;
1870         enum bootmenu_key key = BKEY_NONE;
1871         struct eficonfig_entry *entry, *tmp;
1872
1873         cli_ch_init(cch);
1874         while (1) {
1875                 key = bootmenu_loop(NULL, cch);
1876
1877                 switch (key) {
1878                 case BKEY_PLUS:
1879                         if (efi_menu->active > 0) {
1880                                 list_for_each_safe(pos, n, &efi_menu->list) {
1881                                         entry = list_entry(pos, struct eficonfig_entry, list);
1882                                         if (entry->num == efi_menu->active)
1883                                                 break;
1884                                 }
1885                                 tmp = list_entry(pos->prev, struct eficonfig_entry, list);
1886                                 entry->num--;
1887                                 tmp->num++;
1888                                 list_del(&tmp->list);
1889                                 list_add(&tmp->list, &entry->list);
1890                         }
1891                         fallthrough;
1892                 case BKEY_UP:
1893                         if (efi_menu->active > 0)
1894                                 --efi_menu->active;
1895                         return EFI_NOT_READY;
1896                 case BKEY_MINUS:
1897                         if (efi_menu->active < efi_menu->count - 3) {
1898                                 list_for_each_safe(pos, n, &efi_menu->list) {
1899                                         entry = list_entry(pos, struct eficonfig_entry, list);
1900                                         if (entry->num == efi_menu->active)
1901                                                 break;
1902                                 }
1903                                 tmp = list_entry(pos->next, struct eficonfig_entry, list);
1904                                 entry->num++;
1905                                 tmp->num--;
1906                                 list_del(&entry->list);
1907                                 list_add(&entry->list, &tmp->list);
1908
1909                                 ++efi_menu->active;
1910                         }
1911                         return EFI_NOT_READY;
1912                 case BKEY_DOWN:
1913                         if (efi_menu->active < efi_menu->count - 1)
1914                                 ++efi_menu->active;
1915                         return EFI_NOT_READY;
1916                 case BKEY_SELECT:
1917                         /* "Save" */
1918                         if (efi_menu->active == efi_menu->count - 2)
1919                                 return EFI_SUCCESS;
1920
1921                         /* "Quit" */
1922                         if (efi_menu->active == efi_menu->count - 1)
1923                                 return EFI_ABORTED;
1924
1925                         break;
1926                 case BKEY_SPACE:
1927                         if (efi_menu->active < efi_menu->count - 2) {
1928                                 list_for_each_safe(pos, n, &efi_menu->list) {
1929                                         entry = list_entry(pos, struct eficonfig_entry, list);
1930                                         if (entry->num == efi_menu->active) {
1931                                                 struct eficonfig_boot_order_data *data = entry->data;
1932
1933                                                 data->active = !data->active;
1934                                                 return EFI_NOT_READY;
1935                                         }
1936                                 }
1937                         }
1938                         break;
1939                 case BKEY_QUIT:
1940                         return EFI_ABORTED;
1941                 default:
1942                         /* Pressed key is not valid, no need to regenerate the menu */
1943                         break;
1944                 }
1945         }
1946 }
1947
1948 /**
1949  * eficonfig_add_change_boot_order_entry() - add boot order entry
1950  *
1951  * @efi_menu:   pointer to the efimenu structure
1952  * @boot_index: boot option index to be added
1953  * @active:     flag to include the boot option into BootOrder
1954  * Return:      status code
1955  */
1956 static efi_status_t eficonfig_add_change_boot_order_entry(struct efimenu *efi_menu,
1957                                                           u32 boot_index, bool active)
1958 {
1959         char *title, *p;
1960         efi_status_t ret;
1961         efi_uintn_t size;
1962         void *load_option;
1963         struct efi_load_option lo;
1964         u16 varname[] = u"Boot####";
1965         struct eficonfig_boot_order_data *data;
1966
1967         efi_create_indexed_name(varname, sizeof(varname), "Boot", boot_index);
1968         load_option = efi_get_var(varname, &efi_global_variable_guid, &size);
1969         if (!load_option)
1970                 return EFI_SUCCESS;
1971
1972         ret = efi_deserialize_load_option(&lo, load_option, &size);
1973         if (ret != EFI_SUCCESS)
1974                 goto out;
1975
1976         data = calloc(1, sizeof(*data));
1977         if (!data) {
1978                 ret = EFI_OUT_OF_RESOURCES;
1979                 goto out;
1980         }
1981
1982         title = calloc(1, utf16_utf8_strlen(lo.label) + 1);
1983         if (!title) {
1984                 free(data);
1985                 ret = EFI_OUT_OF_RESOURCES;
1986                 goto out;
1987         }
1988         p = title;
1989         utf16_utf8_strcpy(&p, lo.label);
1990
1991         data->boot_index = boot_index;
1992         data->active = active;
1993
1994         ret = eficonfig_append_menu_entry(efi_menu, title, NULL, data);
1995         if (ret != EFI_SUCCESS) {
1996                 free(data);
1997                 free(title);
1998                 goto out;
1999         }
2000
2001 out:
2002         free(load_option);
2003
2004         return ret;
2005 }
2006
2007 /**
2008  * eficonfig_create_change_boot_order_entry() - create boot order entry
2009  *
2010  * @efi_menu:   pointer to the efimenu structure
2011  * @bootorder:  pointer to the BootOrder variable
2012  * @num:        number of BootOrder entry
2013  * Return:      status code
2014  */
2015 static efi_status_t eficonfig_create_change_boot_order_entry(struct efimenu *efi_menu,
2016                                                              u16 *bootorder, efi_uintn_t num)
2017 {
2018         u32 i;
2019         char *title;
2020         efi_status_t ret;
2021         u16 *var_name16 = NULL;
2022         efi_uintn_t size, buf_size;
2023
2024         /* list the load option in the order of BootOrder variable */
2025         for (i = 0; i < num; i++) {
2026                 if (efi_menu->count >= EFICONFIG_ENTRY_NUM_MAX - 2)
2027                         break;
2028
2029                 ret = eficonfig_add_change_boot_order_entry(efi_menu, bootorder[i], true);
2030                 if (ret != EFI_SUCCESS)
2031                         goto out;
2032         }
2033
2034         /* list the remaining load option not included in the BootOrder */
2035         buf_size = 128;
2036         var_name16 = malloc(buf_size);
2037         if (!var_name16)
2038                 return EFI_OUT_OF_RESOURCES;
2039
2040         var_name16[0] = 0;
2041         for (;;) {
2042                 int index;
2043                 efi_guid_t guid;
2044
2045                 if (efi_menu->count >= EFICONFIG_ENTRY_NUM_MAX - 2)
2046                         break;
2047
2048                 size = buf_size;
2049                 ret = efi_next_variable_name(&buf_size, &var_name16, &guid);
2050                 if (ret == EFI_NOT_FOUND)
2051                         break;
2052                 if (ret != EFI_SUCCESS)
2053                         goto out;
2054
2055                 if (efi_varname_is_load_option(var_name16, &index)) {
2056                         /* If the index is included in the BootOrder, skip it */
2057                         if (search_bootorder(bootorder, num, index, NULL))
2058                                 continue;
2059
2060                         ret = eficonfig_add_change_boot_order_entry(efi_menu, index, false);
2061                         if (ret != EFI_SUCCESS)
2062                                 goto out;
2063                 }
2064         }
2065
2066         /* add "Save" and "Quit" entries */
2067         title = strdup("Save");
2068         if (!title) {
2069                 ret = EFI_OUT_OF_RESOURCES;
2070                 goto out;
2071         }
2072
2073         ret = eficonfig_append_menu_entry(efi_menu, title, NULL, NULL);
2074         if (ret != EFI_SUCCESS)
2075                 goto out;
2076
2077         ret = eficonfig_append_quit_entry(efi_menu);
2078         if (ret != EFI_SUCCESS)
2079                 goto out;
2080
2081         efi_menu->active = 0;
2082 out:
2083         free(var_name16);
2084
2085         return ret;
2086 }
2087
2088 /**
2089  * eficonfig_process_change_boot_order() - handler to change boot order
2090  *
2091  * @data:       pointer to the data for each entry
2092  * Return:      status code
2093  */
2094 static efi_status_t eficonfig_process_change_boot_order(void *data)
2095 {
2096         u32 count;
2097         u16 *bootorder;
2098         efi_status_t ret;
2099         efi_uintn_t num, size;
2100         struct list_head *pos, *n;
2101         struct eficonfig_entry *entry;
2102         struct efimenu *efi_menu;
2103
2104         efi_menu = calloc(1, sizeof(struct efimenu));
2105         if (!efi_menu)
2106                 return EFI_OUT_OF_RESOURCES;
2107
2108         bootorder = efi_get_var(u"BootOrder", &efi_global_variable_guid, &size);
2109
2110         INIT_LIST_HEAD(&efi_menu->list);
2111         num = size / sizeof(u16);
2112         ret = eficonfig_create_change_boot_order_entry(efi_menu, bootorder, num);
2113         if (ret != EFI_SUCCESS)
2114                 goto out;
2115
2116         while (1) {
2117                 eficonfig_display_change_boot_order(efi_menu);
2118
2119                 ret = eficonfig_choice_change_boot_order(efi_menu);
2120                 if (ret == EFI_SUCCESS) {
2121                         u16 *new_bootorder;
2122
2123                         new_bootorder = calloc(1, (efi_menu->count - 2) * sizeof(u16));
2124                         if (!new_bootorder) {
2125                                 ret = EFI_OUT_OF_RESOURCES;
2126                                 goto out;
2127                         }
2128
2129                         /* create new BootOrder  */
2130                         count = 0;
2131                         list_for_each_safe(pos, n, &efi_menu->list) {
2132                                 struct eficonfig_boot_order_data *data;
2133
2134                                 entry = list_entry(pos, struct eficonfig_entry, list);
2135                                 /* exit the loop when iteration reaches "Save" */
2136                                 if (!strncmp(entry->title, "Save", strlen("Save")))
2137                                         break;
2138
2139                                 data = entry->data;
2140                                 if (data->active)
2141                                         new_bootorder[count++] = data->boot_index;
2142                         }
2143
2144                         size = count * sizeof(u16);
2145                         ret = efi_set_variable_int(u"BootOrder", &efi_global_variable_guid,
2146                                                    EFI_VARIABLE_NON_VOLATILE |
2147                                                    EFI_VARIABLE_BOOTSERVICE_ACCESS |
2148                                                    EFI_VARIABLE_RUNTIME_ACCESS,
2149                                                    size, new_bootorder, false);
2150
2151                         free(new_bootorder);
2152                         goto out;
2153                 } else if (ret == EFI_NOT_READY) {
2154                         continue;
2155                 } else {
2156                         goto out;
2157                 }
2158         }
2159 out:
2160         free(bootorder);
2161         list_for_each_safe(pos, n, &efi_menu->list) {
2162                 entry = list_entry(pos, struct eficonfig_entry, list);
2163                 free(entry->data);
2164         }
2165         eficonfig_destroy(efi_menu);
2166
2167         /* to stay the parent menu */
2168         ret = (ret == EFI_ABORTED) ? EFI_NOT_READY : ret;
2169
2170         return ret;
2171 }
2172
2173 /**
2174  * delete_boot_option() - delete selected boot option
2175  *
2176  * @boot_index: boot option index to delete
2177  * Return:      status code
2178  */
2179 static efi_status_t delete_boot_option(u16 boot_index)
2180 {
2181         u16 *bootorder;
2182         u16 varname[9];
2183         efi_status_t ret;
2184         unsigned int index;
2185         efi_uintn_t num, size;
2186
2187         efi_create_indexed_name(varname, sizeof(varname),
2188                                 "Boot", boot_index);
2189         ret = efi_set_variable_int(varname, &efi_global_variable_guid,
2190                                    0, 0, NULL, false);
2191         if (ret != EFI_SUCCESS) {
2192                 log_err("delete boot option(%ls) failed\n", varname);
2193                 return ret;
2194         }
2195
2196         /* update BootOrder if necessary */
2197         bootorder = efi_get_var(u"BootOrder", &efi_global_variable_guid, &size);
2198         if (!bootorder)
2199                 return EFI_SUCCESS;
2200
2201         num = size / sizeof(u16);
2202         if (!search_bootorder(bootorder, num, boot_index, &index))
2203                 return EFI_SUCCESS;
2204
2205         memmove(&bootorder[index], &bootorder[index + 1],
2206                 (num - index - 1) * sizeof(u16));
2207         size -= sizeof(u16);
2208         ret = efi_set_variable_int(u"BootOrder", &efi_global_variable_guid,
2209                                    EFI_VARIABLE_NON_VOLATILE |
2210                                    EFI_VARIABLE_BOOTSERVICE_ACCESS |
2211                                    EFI_VARIABLE_RUNTIME_ACCESS,
2212                                    size, bootorder, false);
2213
2214         return ret;
2215 }
2216
2217 /**
2218  * eficonfig_process_delete_boot_option() - handler to delete boot option
2219  *
2220  * @data:       pointer to the data for each entry
2221  * Return:      status code
2222  */
2223 static efi_status_t eficonfig_process_delete_boot_option(void *data)
2224 {
2225         efi_status_t ret;
2226         unsigned int selected;
2227
2228         while (1) {
2229                 ret = eficonfig_show_boot_selection(&selected);
2230                 if (ret == EFI_SUCCESS)
2231                         ret = delete_boot_option(selected);
2232
2233                 if (ret != EFI_SUCCESS)
2234                         break;
2235         }
2236
2237         /* to stay the parent menu */
2238         ret = (ret == EFI_ABORTED) ? EFI_NOT_READY : ret;
2239
2240         return ret;
2241 }
2242
2243 /**
2244  * eficonfig_enumerate_boot_option() - enumerate the possible bootable media
2245  *
2246  * @opt:                pointer to the media boot option structure
2247  * @volume_handles:     pointer to the efi handles
2248  * @count:              number of efi handle
2249  * Return:              status code
2250  */
2251 efi_status_t eficonfig_enumerate_boot_option(struct eficonfig_media_boot_option *opt,
2252                                              efi_handle_t *volume_handles, efi_status_t count)
2253 {
2254         u32 i;
2255         struct efi_handler *handler;
2256         efi_status_t ret = EFI_SUCCESS;
2257
2258         for (i = 0; i < count; i++) {
2259                 u16 *p;
2260                 u16 dev_name[BOOTMENU_DEVICE_NAME_MAX];
2261                 char *optional_data;
2262                 struct efi_load_option lo;
2263                 char buf[BOOTMENU_DEVICE_NAME_MAX];
2264                 struct efi_device_path *device_path;
2265
2266                 ret = efi_search_protocol(volume_handles[i], &efi_guid_device_path, &handler);
2267                 if (ret != EFI_SUCCESS)
2268                         continue;
2269                 ret = efi_protocol_open(handler, (void **)&device_path,
2270                                         efi_root, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
2271                 if (ret != EFI_SUCCESS)
2272                         continue;
2273
2274                 ret = efi_disk_get_device_name(volume_handles[i], buf, BOOTMENU_DEVICE_NAME_MAX);
2275                 if (ret != EFI_SUCCESS)
2276                         continue;
2277
2278                 p = dev_name;
2279                 utf8_utf16_strncpy(&p, buf, strlen(buf));
2280
2281                 lo.label = dev_name;
2282                 lo.attributes = LOAD_OPTION_ACTIVE;
2283                 lo.file_path = device_path;
2284                 lo.file_path_length = efi_dp_size(device_path) + sizeof(END);
2285                 /*
2286                  * Set the dedicated guid to optional_data, it is used to identify
2287                  * the boot option that automatically generated by the bootmenu.
2288                  * efi_serialize_load_option() expects optional_data is null-terminated
2289                  * utf8 string, so set the "1234567" string to allocate enough space
2290                  * to store guid, instead of realloc the load_option.
2291                  */
2292                 lo.optional_data = "1234567";
2293                 opt[i].size = efi_serialize_load_option(&lo, (u8 **)&opt[i].lo);
2294                 if (!opt[i].size) {
2295                         ret = EFI_OUT_OF_RESOURCES;
2296                         goto out;
2297                 }
2298                 /* set the guid */
2299                 optional_data = (char *)opt[i].lo + (opt[i].size - u16_strsize(u"1234567"));
2300                 memcpy(optional_data, &efi_guid_bootmenu_auto_generated, sizeof(efi_guid_t));
2301         }
2302
2303 out:
2304         return ret;
2305 }
2306
2307 /**
2308  * eficonfig_delete_invalid_boot_option() - delete non-existing boot option
2309  *
2310  * @opt:                pointer to the media boot option structure
2311  * @count:              number of media boot option structure
2312  * Return:              status code
2313  */
2314 efi_status_t eficonfig_delete_invalid_boot_option(struct eficonfig_media_boot_option *opt,
2315                                                   efi_status_t count)
2316 {
2317         efi_uintn_t size;
2318         void *load_option;
2319         u32 i, list_size = 0;
2320         struct efi_load_option lo;
2321         u16 *var_name16 = NULL;
2322         u16 varname[] = u"Boot####";
2323         efi_status_t ret = EFI_SUCCESS;
2324         u16 *delete_index_list = NULL, *p;
2325         efi_uintn_t buf_size;
2326
2327         buf_size = 128;
2328         var_name16 = malloc(buf_size);
2329         if (!var_name16)
2330                 return EFI_OUT_OF_RESOURCES;
2331
2332         var_name16[0] = 0;
2333         for (;;) {
2334                 int index;
2335                 efi_guid_t guid;
2336                 efi_uintn_t tmp;
2337
2338                 ret = efi_next_variable_name(&buf_size, &var_name16, &guid);
2339                 if (ret == EFI_NOT_FOUND) {
2340                         /*
2341                          * EFI_NOT_FOUND indicates we retrieved all EFI variables.
2342                          * This should be treated as success.
2343                          */
2344                         ret = EFI_SUCCESS;
2345                         break;
2346                 }
2347                 if (ret != EFI_SUCCESS)
2348                         goto out;
2349
2350                 if (!efi_varname_is_load_option(var_name16, &index))
2351                         continue;
2352
2353                 efi_create_indexed_name(varname, sizeof(varname), "Boot", index);
2354                 load_option = efi_get_var(varname, &efi_global_variable_guid, &size);
2355                 if (!load_option)
2356                         continue;
2357
2358                 tmp = size;
2359                 ret = efi_deserialize_load_option(&lo, load_option, &size);
2360                 if (ret != EFI_SUCCESS)
2361                         goto next;
2362
2363                 if (size >= sizeof(efi_guid_bootmenu_auto_generated) &&
2364                     !guidcmp(lo.optional_data, &efi_guid_bootmenu_auto_generated)) {
2365                         for (i = 0; i < count; i++) {
2366                                 if (opt[i].size == tmp &&
2367                                     memcmp(opt[i].lo, load_option, tmp) == 0) {
2368                                         opt[i].exist = true;
2369                                         break;
2370                                 }
2371                         }
2372
2373                         /*
2374                          * The entire list of variables must be retrieved by
2375                          * efi_get_next_variable_name_int() before deleting the invalid
2376                          * boot option, just save the index here.
2377                          */
2378                         if (i == count) {
2379                                 p = realloc(delete_index_list, sizeof(u32) *
2380                                             (list_size + 1));
2381                                 if (!p) {
2382                                         ret = EFI_OUT_OF_RESOURCES;
2383                                         goto out;
2384                                 }
2385                                 delete_index_list = p;
2386                                 delete_index_list[list_size++] = index;
2387                         }
2388                 }
2389 next:
2390                 free(load_option);
2391         }
2392
2393         /* delete all invalid boot options */
2394         for (i = 0; i < list_size; i++) {
2395                 ret = delete_boot_option(delete_index_list[i]);
2396                 if (ret != EFI_SUCCESS)
2397                         goto out;
2398         }
2399
2400 out:
2401         free(var_name16);
2402         free(delete_index_list);
2403
2404         return ret;
2405 }
2406
2407 /**
2408  * eficonfig_generate_media_device_boot_option() - generate the media device boot option
2409  *
2410  * This function enumerates all devices supporting EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
2411  * and generate the bootmenu entries.
2412  * This function also provide the BOOT#### variable maintenance for
2413  * the media device entries.
2414  *   - Automatically create the BOOT#### variable for the newly detected device,
2415  *     this BOOT#### variable is distinguished by the special GUID
2416  *     stored in the EFI_LOAD_OPTION.optional_data
2417  *   - If the device is not attached to the system, the associated BOOT#### variable
2418  *     is automatically deleted.
2419  *
2420  * Return:      status code
2421  */
2422 efi_status_t eficonfig_generate_media_device_boot_option(void)
2423 {
2424         u32 i;
2425         efi_status_t ret;
2426         efi_uintn_t count;
2427         efi_handle_t *volume_handles = NULL;
2428         struct eficonfig_media_boot_option *opt = NULL;
2429
2430         ret = efi_locate_handle_buffer_int(BY_PROTOCOL, &efi_simple_file_system_protocol_guid,
2431                                            NULL, &count, (efi_handle_t **)&volume_handles);
2432         if (ret != EFI_SUCCESS)
2433                 return ret;
2434
2435         opt = calloc(count, sizeof(struct eficonfig_media_boot_option));
2436         if (!opt)
2437                 goto out;
2438
2439         /* enumerate all devices supporting EFI_SIMPLE_FILE_SYSTEM_PROTOCOL */
2440         ret = eficonfig_enumerate_boot_option(opt, volume_handles, count);
2441         if (ret != EFI_SUCCESS)
2442                 goto out;
2443
2444         /*
2445          * System hardware configuration may vary depending on the user setup.
2446          * The boot option is automatically added by the bootmenu.
2447          * If the device is not attached to the system, the boot option needs
2448          * to be deleted.
2449          */
2450         ret = eficonfig_delete_invalid_boot_option(opt, count);
2451         if (ret != EFI_SUCCESS)
2452                 goto out;
2453
2454         /* add non-existent boot option */
2455         for (i = 0; i < count; i++) {
2456                 u32 boot_index;
2457                 u16 var_name[9];
2458
2459                 if (!opt[i].exist) {
2460                         ret = eficonfig_get_unused_bootoption(var_name, sizeof(var_name),
2461                                                               &boot_index);
2462                         if (ret != EFI_SUCCESS)
2463                                 goto out;
2464
2465                         ret = efi_set_variable_int(var_name, &efi_global_variable_guid,
2466                                                    EFI_VARIABLE_NON_VOLATILE |
2467                                                    EFI_VARIABLE_BOOTSERVICE_ACCESS |
2468                                                    EFI_VARIABLE_RUNTIME_ACCESS,
2469                                                    opt[i].size, opt[i].lo, false);
2470                         if (ret != EFI_SUCCESS)
2471                                 goto out;
2472
2473                         ret = eficonfig_append_bootorder(boot_index);
2474                         if (ret != EFI_SUCCESS) {
2475                                 efi_set_variable_int(var_name, &efi_global_variable_guid,
2476                                                      0, 0, NULL, false);
2477                                 goto out;
2478                         }
2479                 }
2480         }
2481
2482 out:
2483         if (opt) {
2484                 for (i = 0; i < count; i++)
2485                         free(opt[i].lo);
2486         }
2487         free(opt);
2488         efi_free_pool(volume_handles);
2489
2490         return ret;
2491 }
2492
2493 /**
2494  * eficonfig_init() - do required initialization for eficonfig command
2495  *
2496  * Return:      status code
2497  */
2498 static efi_status_t eficonfig_init(void)
2499 {
2500         efi_status_t ret = EFI_SUCCESS;
2501         static bool init;
2502         struct efi_handler *handler;
2503
2504         if (!init) {
2505                 ret = efi_search_protocol(efi_root, &efi_guid_text_input_protocol, &handler);
2506                 if (ret != EFI_SUCCESS)
2507                         return ret;
2508
2509                 ret = efi_protocol_open(handler, (void **)&cin, efi_root, NULL,
2510                                         EFI_OPEN_PROTOCOL_GET_PROTOCOL);
2511                 if (ret != EFI_SUCCESS)
2512                         return ret;
2513         }
2514
2515         init = true;
2516
2517         return ret;
2518 }
2519
2520 static const struct eficonfig_item maintenance_menu_items[] = {
2521         {"Add Boot Option", eficonfig_process_add_boot_option},
2522         {"Edit Boot Option", eficonfig_process_edit_boot_option},
2523         {"Change Boot Order", eficonfig_process_change_boot_order},
2524         {"Delete Boot Option", eficonfig_process_delete_boot_option},
2525 #if (CONFIG_IS_ENABLED(EFI_SECURE_BOOT) && CONFIG_IS_ENABLED(EFI_MM_COMM_TEE))
2526         {"Secure Boot Configuration", eficonfig_process_secure_boot_config},
2527 #endif
2528         {"Quit", eficonfig_process_quit},
2529 };
2530
2531 /**
2532  * do_eficonfig() - execute `eficonfig` command
2533  *
2534  * @cmdtp:      table entry describing command
2535  * @flag:       bitmap indicating how the command was invoked
2536  * @argc:       number of arguments
2537  * @argv:       command line arguments
2538  * Return:      status code
2539  */
2540 static int do_eficonfig(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
2541 {
2542         efi_status_t ret;
2543         struct efimenu *efi_menu;
2544
2545         if (argc > 1)
2546                 return CMD_RET_USAGE;
2547
2548         ret = efi_init_obj_list();
2549         if (ret != EFI_SUCCESS) {
2550                 log_err("Error: Cannot initialize UEFI sub-system, r = %lu\n",
2551                         ret & ~EFI_ERROR_MASK);
2552
2553                 return CMD_RET_FAILURE;
2554         }
2555
2556         ret = eficonfig_init();
2557         if (ret != EFI_SUCCESS)
2558                 return CMD_RET_FAILURE;
2559
2560         ret = eficonfig_generate_media_device_boot_option();
2561         if (ret != EFI_SUCCESS && ret != EFI_NOT_FOUND)
2562                 return ret;
2563
2564         while (1) {
2565                 efi_menu = eficonfig_create_fixed_menu(maintenance_menu_items,
2566                                                        ARRAY_SIZE(maintenance_menu_items));
2567                 if (!efi_menu)
2568                         return CMD_RET_FAILURE;
2569
2570                 ret = eficonfig_process_common(efi_menu, "  ** UEFI Maintenance Menu **");
2571                 eficonfig_destroy(efi_menu);
2572
2573                 if (ret == EFI_ABORTED)
2574                         break;
2575         }
2576
2577         return CMD_RET_SUCCESS;
2578 }
2579
2580 U_BOOT_CMD(
2581         eficonfig, 1, 0, do_eficonfig,
2582         "provide menu-driven UEFI variable maintenance interface",
2583         ""
2584 );