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