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