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