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