1 // SPDX-License-Identifier: GPL-2.0+
3 * UEFI Shell-like command
5 * Copyright (c) 2018 AKASHI Takahiro, Linaro Limited
11 #include <efi_loader.h>
12 #include <environment.h>
16 #include <linux/ctype.h>
18 #define RT systab.runtime
21 * do_efi_boot_add() - set UEFI load option
23 * @cmdtp: Command table
25 * @argc: Number of arguments
26 * @argv: Argument array
27 * Return: CMD_RET_SUCCESS on success,
28 * CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
30 * Implement efidebug "boot add" sub-command.
31 * Create or change UEFI load option.
32 * - boot add <id> <label> <interface> <devnum>[:<part>] <file> <options>
34 static int do_efi_boot_add(cmd_tbl_t *cmdtp, int flag,
35 int argc, char * const argv[])
40 u16 var_name16[9], *p;
42 size_t label_len, label_len16;
44 struct efi_device_path *device_path = NULL, *file_path = NULL;
45 struct efi_load_option lo;
50 if (argc < 6 || argc > 7)
53 id = (int)simple_strtoul(argv[1], &endp, 16);
54 if (*endp != '\0' || id > 0xffff)
55 return CMD_RET_FAILURE;
57 sprintf(var_name, "Boot%04X", id);
59 utf8_utf16_strncpy(&p, var_name, 9);
61 guid = efi_global_variable_guid;
64 lo.attributes = LOAD_OPTION_ACTIVE; /* always ACTIVE */
67 label_len = strlen(argv[2]);
68 label_len16 = utf8_utf16_strnlen(argv[2], label_len);
69 label = malloc((label_len16 + 1) * sizeof(u16));
71 return CMD_RET_FAILURE;
72 lo.label = label; /* label will be changed below */
73 utf8_utf16_strncpy(&label, argv[2], label_len);
76 ret = efi_dp_from_name(argv[3], argv[4], argv[5], &device_path,
78 if (ret != EFI_SUCCESS) {
79 printf("Cannot create device path for \"%s %s\"\n",
81 ret = CMD_RET_FAILURE;
84 lo.file_path = file_path;
85 lo.file_path_length = efi_dp_size(file_path)
86 + sizeof(struct efi_device_path); /* for END */
89 lo.optional_data = (u8 *)(argc == 6 ? "" : argv[6]);
91 size = efi_serialize_load_option(&lo, (u8 **)&data);
93 ret = CMD_RET_FAILURE;
97 ret = EFI_CALL(RT->set_variable(var_name16, &guid,
98 EFI_VARIABLE_BOOTSERVICE_ACCESS |
99 EFI_VARIABLE_RUNTIME_ACCESS,
101 ret = (ret == EFI_SUCCESS ? CMD_RET_SUCCESS : CMD_RET_FAILURE);
104 efi_free_pool(device_path);
105 efi_free_pool(file_path);
112 * do_efi_boot_rm() - delete UEFI load options
114 * @cmdtp: Command table
115 * @flag: Command flag
116 * @argc: Number of arguments
117 * @argv: Argument array
118 * Return: CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
120 * Implement efidebug "boot rm" sub-command.
121 * Delete UEFI load options.
124 static int do_efi_boot_rm(cmd_tbl_t *cmdtp, int flag,
125 int argc, char * const argv[])
135 return CMD_RET_USAGE;
137 guid = efi_global_variable_guid;
138 for (i = 1; i < argc; i++, argv++) {
139 id = (int)simple_strtoul(argv[1], &endp, 16);
140 if (*endp != '\0' || id > 0xffff)
141 return CMD_RET_FAILURE;
143 sprintf(var_name, "Boot%04X", id);
144 utf8_utf16_strncpy((u16 **)&var_name16, var_name, 9);
146 ret = EFI_CALL(RT->set_variable(var_name16, &guid, 0, 0, NULL));
148 printf("cannot remove Boot%04X", id);
149 return CMD_RET_FAILURE;
153 return CMD_RET_SUCCESS;
157 * show_efi_boot_opt_data() - dump UEFI load option
159 * @id: Load option number
160 * @data: Value of UEFI load option variable
162 * Decode the value of UEFI load option variable and print information.
164 static void show_efi_boot_opt_data(int id, void *data)
166 struct efi_load_option lo;
168 size_t label_len16, label_len;
171 efi_deserialize_load_option(&lo, data);
173 label_len16 = u16_strlen(lo.label);
174 label_len = utf16_utf8_strnlen(lo.label, label_len16);
175 label = malloc(label_len + 1);
179 utf16_utf8_strncpy(&p, lo.label, label_len16);
181 printf("Boot%04X:\n", id);
182 printf("\tattributes: %c%c%c (0x%08x)\n",
184 lo.attributes & LOAD_OPTION_ACTIVE ? 'A' : '-',
185 /* FORCE RECONNECT */
186 lo.attributes & LOAD_OPTION_FORCE_RECONNECT ? 'R' : '-',
188 lo.attributes & LOAD_OPTION_HIDDEN ? 'H' : '-',
190 printf("\tlabel: %s\n", label);
192 dp_str = efi_dp_str(lo.file_path);
193 printf("\tfile_path: %ls\n", dp_str);
194 efi_free_pool(dp_str);
196 printf("\tdata: %s\n", lo.optional_data);
202 * show_efi_boot_opt() - dump UEFI load option
204 * @id: Load option number
206 * Dump information defined by UEFI load option.
208 static void show_efi_boot_opt(int id)
211 u16 var_name16[9], *p;
217 sprintf(var_name, "Boot%04X", id);
219 utf8_utf16_strncpy(&p, var_name, 9);
220 guid = efi_global_variable_guid;
223 ret = EFI_CALL(RT->get_variable(var_name16, &guid, NULL, &size, NULL));
224 if (ret == (int)EFI_BUFFER_TOO_SMALL) {
226 ret = EFI_CALL(RT->get_variable(var_name16, &guid, NULL, &size,
229 if (ret == EFI_SUCCESS)
230 show_efi_boot_opt_data(id, data);
231 else if (ret == EFI_NOT_FOUND)
232 printf("Boot%04X: not found\n", id);
238 * show_efi_boot_dump() - dump all UEFI load options
240 * @cmdtp: Command table
241 * @flag: Command flag
242 * @argc: Number of arguments
243 * @argv: Argument array
244 * Return: CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
246 * Implement efidebug "boot dump" sub-command.
247 * Dump information of all UEFI load options defined.
250 static int do_efi_boot_dump(cmd_tbl_t *cmdtp, int flag,
251 int argc, char * const argv[])
254 char * const regexlist[] = {regex};
255 char *variables = NULL, *boot, *value;
260 return CMD_RET_USAGE;
262 snprintf(regex, 256, "efi_.*-.*-.*-.*-.*_Boot[0-9A-F]+");
264 /* TODO: use GetNextVariableName? */
265 len = hexport_r(&env_htab, '\n', H_MATCH_REGEX | H_MATCH_KEY,
266 &variables, 0, 1, regexlist);
269 return CMD_RET_SUCCESS;
272 return CMD_RET_FAILURE;
276 value = strstr(boot, "Boot") + 4;
277 id = (int)simple_strtoul(value, NULL, 16);
278 show_efi_boot_opt(id);
279 boot = strchr(boot, '\n');
286 return CMD_RET_SUCCESS;
290 * show_efi_boot_order() - show order of UEFI load options
292 * Return: CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
294 * Show order of UEFI load options defined by BootOrder variable.
296 static int show_efi_boot_order(void)
299 u16 *bootorder = NULL;
303 u16 var_name16[9], *p16;
305 struct efi_load_option lo;
307 size_t label_len16, label_len;
310 guid = efi_global_variable_guid;
312 ret = EFI_CALL(RT->get_variable(L"BootOrder", &guid, NULL, &size,
314 if (ret == EFI_BUFFER_TOO_SMALL) {
315 bootorder = malloc(size);
316 ret = EFI_CALL(RT->get_variable(L"BootOrder", &guid, NULL,
319 if (ret == EFI_NOT_FOUND) {
320 printf("BootOrder not defined\n");
321 ret = CMD_RET_SUCCESS;
323 } else if (ret != EFI_SUCCESS) {
324 ret = CMD_RET_FAILURE;
328 num = size / sizeof(u16);
329 for (i = 0; i < num; i++) {
330 sprintf(var_name, "Boot%04X", bootorder[i]);
332 utf8_utf16_strncpy(&p16, var_name, 9);
335 ret = EFI_CALL(RT->get_variable(var_name16, &guid, NULL, &size,
337 if (ret != EFI_BUFFER_TOO_SMALL) {
338 printf("%2d: Boot%04X: (not defined)\n",
339 i + 1, bootorder[i]);
345 ret = CMD_RET_FAILURE;
348 ret = EFI_CALL(RT->get_variable(var_name16, &guid, NULL, &size,
350 if (ret != EFI_SUCCESS) {
352 ret = CMD_RET_FAILURE;
356 efi_deserialize_load_option(&lo, data);
358 label_len16 = u16_strlen(lo.label);
359 label_len = utf16_utf8_strnlen(lo.label, label_len16);
360 label = malloc(label_len + 1);
363 ret = CMD_RET_FAILURE;
367 utf16_utf8_strncpy(&p, lo.label, label_len16);
368 printf("%2d: Boot%04X: %s\n", i + 1, bootorder[i], label);
380 * do_efi_boot_next() - manage UEFI BootNext variable
382 * @cmdtp: Command table
383 * @flag: Command flag
384 * @argc: Number of arguments
385 * @argv: Argument array
386 * Return: CMD_RET_SUCCESS on success,
387 * CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
389 * Implement efidebug "boot next" sub-command.
390 * Set BootNext variable.
393 static int do_efi_boot_next(cmd_tbl_t *cmdtp, int flag,
394 int argc, char * const argv[])
403 return CMD_RET_USAGE;
405 bootnext = (u16)simple_strtoul(argv[1], &endp, 16);
406 if (*endp != '\0' || bootnext > 0xffff) {
407 printf("invalid value: %s\n", argv[1]);
408 ret = CMD_RET_FAILURE;
412 guid = efi_global_variable_guid;
414 ret = EFI_CALL(RT->set_variable(L"BootNext", &guid,
415 EFI_VARIABLE_BOOTSERVICE_ACCESS |
416 EFI_VARIABLE_RUNTIME_ACCESS,
418 ret = (ret == EFI_SUCCESS ? CMD_RET_SUCCESS : CMD_RET_FAILURE);
424 * do_efi_boot_order() - manage UEFI BootOrder variable
426 * @cmdtp: Command table
427 * @flag: Command flag
428 * @argc: Number of arguments
429 * @argv: Argument array
430 * Return: CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
432 * Implement efidebug "boot order" sub-command.
433 * Show order of UEFI load options, or change it in BootOrder variable.
434 * - boot order [<id> ...]
436 static int do_efi_boot_order(cmd_tbl_t *cmdtp, int flag,
437 int argc, char * const argv[])
439 u16 *bootorder = NULL;
447 return show_efi_boot_order();
452 size = argc * sizeof(u16);
453 bootorder = malloc(size);
455 return CMD_RET_FAILURE;
457 for (i = 0; i < argc; i++) {
458 id = (int)simple_strtoul(argv[i], &endp, 16);
459 if (*endp != '\0' || id > 0xffff) {
460 printf("invalid value: %s\n", argv[i]);
461 ret = CMD_RET_FAILURE;
465 bootorder[i] = (u16)id;
468 guid = efi_global_variable_guid;
469 ret = EFI_CALL(RT->set_variable(L"BootOrder", &guid,
470 EFI_VARIABLE_BOOTSERVICE_ACCESS |
471 EFI_VARIABLE_RUNTIME_ACCESS,
473 ret = (ret == EFI_SUCCESS ? CMD_RET_SUCCESS : CMD_RET_FAILURE);
480 static cmd_tbl_t cmd_efidebug_boot_sub[] = {
481 U_BOOT_CMD_MKENT(add, CONFIG_SYS_MAXARGS, 1, do_efi_boot_add, "", ""),
482 U_BOOT_CMD_MKENT(rm, CONFIG_SYS_MAXARGS, 1, do_efi_boot_rm, "", ""),
483 U_BOOT_CMD_MKENT(dump, CONFIG_SYS_MAXARGS, 1, do_efi_boot_dump, "", ""),
484 U_BOOT_CMD_MKENT(next, CONFIG_SYS_MAXARGS, 1, do_efi_boot_next, "", ""),
485 U_BOOT_CMD_MKENT(order, CONFIG_SYS_MAXARGS, 1, do_efi_boot_order,
490 * do_efi_boot_opt() - manage UEFI load options
492 * @cmdtp: Command table
493 * @flag: Command flag
494 * @argc: Number of arguments
495 * @argv: Argument array
496 * Return: CMD_RET_SUCCESS on success,
497 * CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
499 * Implement efidebug "boot" sub-command.
500 * See above for details of sub-commands.
502 static int do_efi_boot_opt(cmd_tbl_t *cmdtp, int flag,
503 int argc, char * const argv[])
508 return CMD_RET_USAGE;
512 cp = find_cmd_tbl(argv[0], cmd_efidebug_boot_sub,
513 ARRAY_SIZE(cmd_efidebug_boot_sub));
515 return CMD_RET_USAGE;
517 return cp->cmd(cmdtp, flag, argc, argv);
520 static cmd_tbl_t cmd_efidebug_sub[] = {
521 U_BOOT_CMD_MKENT(boot, CONFIG_SYS_MAXARGS, 1, do_efi_boot_opt, "", ""),
525 * do_efidebug() - display and configure UEFI environment
527 * @cmdtp: Command table
528 * @flag: Command flag
529 * @argc: Number of arguments
530 * @argv: Argument array
531 * Return: CMD_RET_SUCCESS on success,
532 * CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
534 * Implement efidebug command which allows us to display and
535 * configure UEFI environment.
536 * See above for details of sub-commands.
538 static int do_efidebug(cmd_tbl_t *cmdtp, int flag,
539 int argc, char * const argv[])
545 return CMD_RET_USAGE;
549 /* Initialize UEFI drivers */
550 r = efi_init_obj_list();
551 if (r != EFI_SUCCESS) {
552 printf("Error: Cannot initialize UEFI sub-system, r = %lu\n",
553 r & ~EFI_ERROR_MASK);
554 return CMD_RET_FAILURE;
557 cp = find_cmd_tbl(argv[0], cmd_efidebug_sub,
558 ARRAY_SIZE(cmd_efidebug_sub));
560 return CMD_RET_USAGE;
562 return cp->cmd(cmdtp, flag, argc, argv);
565 #ifdef CONFIG_SYS_LONGHELP
566 static char efidebug_help_text[] =
567 " - UEFI Shell-like interface to configure UEFI environment\n"
569 "efidebug boot add <bootid> <label> <interface> <devnum>[:<part>] <file path> [<load options>]\n"
570 " - set UEFI BootXXXX variable\n"
571 " <load options> will be passed to UEFI application\n"
572 "efidebug boot rm <bootid#1> [<bootid#2> [<bootid#3> [...]]]\n"
573 " - delete UEFI BootXXXX variables\n"
574 "efidebug boot dump\n"
575 " - dump all UEFI BootXXXX variables\n"
576 "efidebug boot next <bootid>\n"
577 " - set UEFI BootNext variable\n"
578 "efidebug boot order [<bootid#1> [<bootid#2> [<bootid#3> [...]]]]\n"
579 " - set/show UEFI boot order\n"
584 efidebug, 10, 0, do_efidebug,
585 "Configure UEFI environment",