Merge tag 'ti-v2020.10-rc1' of https://gitlab.denx.de/u-boot/custodians/u-boot-ti
[platform/kernel/u-boot.git] / cmd / nvedit_efi.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  *  Integrate UEFI variables to u-boot env interface
4  *
5  *  Copyright (c) 2018 AKASHI Takahiro, Linaro Limited
6  */
7
8 #include <charset.h>
9 #include <common.h>
10 #include <command.h>
11 #include <efi_loader.h>
12 #include <efi_variable.h>
13 #include <env.h>
14 #include <exports.h>
15 #include <hexdump.h>
16 #include <malloc.h>
17 #include <mapmem.h>
18 #include <rtc.h>
19 #include <uuid.h>
20 #include <linux/kernel.h>
21
22 /*
23  * From efi_variable.c,
24  *
25  * Mapping between UEFI variables and u-boot variables:
26  *
27  *   efi_$guid_$varname = {attributes}(type)value
28  */
29
30 static const struct {
31         u32 mask;
32         char *text;
33 } efi_var_attrs[] = {
34         {EFI_VARIABLE_NON_VOLATILE, "NV"},
35         {EFI_VARIABLE_BOOTSERVICE_ACCESS, "BS"},
36         {EFI_VARIABLE_RUNTIME_ACCESS, "RT"},
37         {EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, "AW"},
38         {EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS, "AT"},
39         {EFI_VARIABLE_READ_ONLY, "RO"},
40 };
41
42 static const struct {
43         efi_guid_t guid;
44         char *text;
45 } efi_guid_text[] = {
46         /* signature database */
47         {EFI_GLOBAL_VARIABLE_GUID, "EFI_GLOBAL_VARIABLE_GUID"},
48         {EFI_IMAGE_SECURITY_DATABASE_GUID, "EFI_IMAGE_SECURITY_DATABASE_GUID"},
49         /* certificate type */
50         {EFI_CERT_SHA256_GUID, "EFI_CERT_SHA256_GUID"},
51         {EFI_CERT_X509_GUID, "EFI_CERT_X509_GUID"},
52         {EFI_CERT_TYPE_PKCS7_GUID, "EFI_CERT_TYPE_PKCS7_GUID"},
53 };
54
55 /* "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" */
56 static char unknown_guid[37];
57
58 /**
59  * efi_guid_to_str() - convert guid to readable name
60  *
61  * @guid:       GUID
62  * Return:      string for GUID
63  *
64  * convert guid to readable name
65  */
66 static const char *efi_guid_to_str(const efi_guid_t *guid)
67 {
68         int i;
69
70         for (i = 0; i < ARRAY_SIZE(efi_guid_text); i++)
71                 if (!guidcmp(guid, &efi_guid_text[i].guid))
72                         return efi_guid_text[i].text;
73
74         uuid_bin_to_str((unsigned char *)guid->b, unknown_guid,
75                         UUID_STR_FORMAT_GUID);
76
77         return unknown_guid;
78 }
79
80 /**
81  * efi_dump_single_var() - show information about a UEFI variable
82  *
83  * @name:       Name of the variable
84  * @guid:       Vendor GUID
85  * @verbose:    if true, dump data
86  *
87  * Show information encoded in one UEFI variable
88  */
89 static void efi_dump_single_var(u16 *name, const efi_guid_t *guid, bool verbose)
90 {
91         u32 attributes;
92         u8 *data;
93         u64 time;
94         struct rtc_time tm;
95         efi_uintn_t size;
96         int count, i;
97         efi_status_t ret;
98
99         data = NULL;
100         size = 0;
101         ret = efi_get_variable_int(name, guid, &attributes, &size, data, &time);
102         if (ret == EFI_BUFFER_TOO_SMALL) {
103                 data = malloc(size);
104                 if (!data)
105                         goto out;
106
107                 ret = efi_get_variable_int(name, guid, &attributes, &size,
108                                            data, &time);
109         }
110         if (ret == EFI_NOT_FOUND) {
111                 printf("Error: \"%ls\" not defined\n", name);
112                 goto out;
113         }
114         if (ret != EFI_SUCCESS)
115                 goto out;
116
117         rtc_to_tm(time, &tm);
118         printf("%ls:\n    %s:\n", name, efi_guid_to_str(guid));
119         if (attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)
120                 printf("    %04d-%02d-%02d %02d:%02d:%02d\n", tm.tm_year,
121                        tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
122         printf("    ");
123         for (count = 0, i = 0; i < ARRAY_SIZE(efi_var_attrs); i++)
124                 if (attributes & efi_var_attrs[i].mask) {
125                         if (count)
126                                 putc('|');
127                         count++;
128                         puts(efi_var_attrs[i].text);
129                 }
130         printf(", DataSize = 0x%zx\n", size);
131         if (verbose)
132                 print_hex_dump("    ", DUMP_PREFIX_OFFSET, 16, 1,
133                                data, size, true);
134
135 out:
136         free(data);
137 }
138
139 /**
140  * efi_dump_vars() - show information about named UEFI variables
141  *
142  * @argc:       Number of arguments (variables)
143  * @argv:       Argument (variable name) array
144  * @verbose:    if true, dump data
145  * Return:      CMD_RET_SUCCESS on success, or CMD_RET_RET_FAILURE
146  *
147  * Show information encoded in named UEFI variables
148  */
149 static int efi_dump_vars(int argc,  char *const argv[],
150                          const efi_guid_t *guid, bool verbose)
151 {
152         u16 *var_name16, *p;
153         efi_uintn_t buf_size, size;
154
155         buf_size = 128;
156         var_name16 = malloc(buf_size);
157         if (!var_name16)
158                 return CMD_RET_FAILURE;
159
160         for (; argc > 0; argc--, argv++) {
161                 size = (utf8_utf16_strlen(argv[0]) + 1) * sizeof(u16);
162                 if (buf_size < size) {
163                         buf_size = size;
164                         p = realloc(var_name16, buf_size);
165                         if (!p) {
166                                 free(var_name16);
167                                 return CMD_RET_FAILURE;
168                         }
169                         var_name16 = p;
170                 }
171
172                 p = var_name16;
173                 utf8_utf16_strcpy(&p, argv[0]);
174
175                 efi_dump_single_var(var_name16, guid, verbose);
176         }
177
178         free(var_name16);
179
180         return CMD_RET_SUCCESS;
181 }
182
183 static bool match_name(int argc, char *const argv[], u16 *var_name16)
184 {
185         char *buf, *p;
186         size_t buflen;
187         int i;
188         bool result = false;
189
190         buflen = utf16_utf8_strlen(var_name16) + 1;
191         buf = calloc(1, buflen);
192         if (!buf)
193                 return result;
194
195         p = buf;
196         utf16_utf8_strcpy(&p, var_name16);
197
198         for (i = 0; i < argc; argc--, argv++) {
199                 if (!strcmp(buf, argv[i])) {
200                         result = true;
201                         goto out;
202                 }
203         }
204
205 out:
206         free(buf);
207
208         return result;
209 }
210
211 /**
212  * efi_dump_var_all() - show information about all the UEFI variables
213  *
214  * @argc:       Number of arguments (variables)
215  * @argv:       Argument (variable name) array
216  * @verbose:    if true, dump data
217  * Return:      CMD_RET_SUCCESS on success, or CMD_RET_RET_FAILURE
218  *
219  * Show information encoded in all the UEFI variables
220  */
221 static int efi_dump_var_all(int argc,  char *const argv[],
222                             const efi_guid_t *guid_p, bool verbose)
223 {
224         u16 *var_name16, *p;
225         efi_uintn_t buf_size, size;
226         efi_guid_t guid;
227         efi_status_t ret;
228
229         if (argc && guid_p)
230                 /* simplified case */
231                 return efi_dump_vars(argc, argv, guid_p, verbose);
232
233         buf_size = 128;
234         var_name16 = malloc(buf_size);
235         if (!var_name16)
236                 return CMD_RET_FAILURE;
237
238         var_name16[0] = 0;
239         for (;;) {
240                 size = buf_size;
241                 ret = EFI_CALL(efi_get_next_variable_name(&size, var_name16,
242                                                           &guid));
243                 if (ret == EFI_NOT_FOUND)
244                         break;
245                 if (ret == EFI_BUFFER_TOO_SMALL) {
246                         buf_size = size;
247                         p = realloc(var_name16, buf_size);
248                         if (!p) {
249                                 free(var_name16);
250                                 return CMD_RET_FAILURE;
251                         }
252                         var_name16 = p;
253                         ret = EFI_CALL(efi_get_next_variable_name(&size,
254                                                                   var_name16,
255                                                                   &guid));
256                 }
257                 if (ret != EFI_SUCCESS) {
258                         free(var_name16);
259                         return CMD_RET_FAILURE;
260                 }
261
262                 if ((!guid_p || !guidcmp(guid_p, &guid)) &&
263                     (!argc || match_name(argc, argv, var_name16)))
264                         efi_dump_single_var(var_name16, &guid, verbose);
265         }
266
267         free(var_name16);
268
269         return CMD_RET_SUCCESS;
270 }
271
272 /**
273  * do_env_print_efi() - show information about UEFI variables
274  *
275  * @cmdtp:      Command table
276  * @flag:       Command flag
277  * @argc:       Number of arguments
278  * @argv:       Argument array
279  * Return:      CMD_RET_SUCCESS on success, or CMD_RET_RET_FAILURE
280  *
281  * This function is for "env print -e" or "printenv -e" command:
282  *   => env print -e [-n] [-guid <guid> | -all] [var [...]]
283  * If one or more variable names are specified, show information
284  * named UEFI variables, otherwise show all the UEFI variables.
285  */
286 int do_env_print_efi(struct cmd_tbl *cmdtp, int flag, int argc,
287                      char *const argv[])
288 {
289         efi_guid_t guid;
290         const efi_guid_t *guid_p;
291         bool default_guid, guid_any, verbose;
292         efi_status_t ret;
293
294         /* Initialize EFI drivers */
295         ret = efi_init_obj_list();
296         if (ret != EFI_SUCCESS) {
297                 printf("Error: Cannot initialize UEFI sub-system, r = %lu\n",
298                        ret & ~EFI_ERROR_MASK);
299                 return CMD_RET_FAILURE;
300         }
301
302         default_guid = true;
303         guid_any = false;
304         verbose = true;
305         for (argc--, argv++; argc > 0 && argv[0][0] == '-'; argc--, argv++) {
306                 if (!strcmp(argv[0], "-guid")) {
307                         if (argc == 1)
308                                 return CMD_RET_USAGE;
309
310                         /* -a already specified */
311                         if (!default_guid && guid_any)
312                                 return CMD_RET_USAGE;
313
314                         argc--;
315                         argv++;
316                         if (uuid_str_to_bin(argv[0], guid.b,
317                                             UUID_STR_FORMAT_GUID))
318                                 return CMD_RET_USAGE;
319                         default_guid = false;
320                 } else if (!strcmp(argv[0], "-all")) {
321                         /* -guid already specified */
322                         if (!default_guid && !guid_any)
323                                 return CMD_RET_USAGE;
324
325                         guid_any = true;
326                         default_guid = false;
327                 } else if (!strcmp(argv[0], "-n")) {
328                         verbose = false;
329                 } else {
330                         return CMD_RET_USAGE;
331                 }
332         }
333
334         if (guid_any)
335                 guid_p = NULL;
336         else if (default_guid)
337                 guid_p = &efi_global_variable_guid;
338         else
339                 guid_p = (const efi_guid_t *)guid.b;
340
341         /* enumerate and show all UEFI variables */
342         return efi_dump_var_all(argc, argv, guid_p, verbose);
343 }
344
345 /**
346  * append_value() - encode UEFI variable's value
347  * @bufp:       Buffer of encoded UEFI variable's value
348  * @sizep:      Size of buffer
349  * @data:       data to be encoded into the value
350  * Return:      0 on success, -1 otherwise
351  *
352  * Interpret a given data string and append it to buffer.
353  * Buffer will be realloc'ed if necessary.
354  *
355  * Currently supported formats are:
356  *   =0x0123...:                Hexadecimal number
357  *   =H0123...:                 Hexadecimal-byte array
358  *   ="...", =S"..." or <string>:
359  *                              String
360  */
361 static int append_value(char **bufp, size_t *sizep, char *data)
362 {
363         char *tmp_buf = NULL, *new_buf = NULL, *value;
364         unsigned long len = 0;
365
366         if (!strncmp(data, "=0x", 2)) { /* hexadecimal number */
367                 union {
368                         u8 u8;
369                         u16 u16;
370                         u32 u32;
371                         u64 u64;
372                 } tmp_data;
373                 unsigned long hex_value;
374                 void *hex_ptr;
375
376                 data += 3;
377                 len = strlen(data);
378                 if ((len & 0x1)) /* not multiple of two */
379                         return -1;
380
381                 len /= 2;
382                 if (len > 8)
383                         return -1;
384                 else if (len > 4)
385                         len = 8;
386                 else if (len > 2)
387                         len = 4;
388
389                 /* convert hex hexadecimal number */
390                 if (strict_strtoul(data, 16, &hex_value) < 0)
391                         return -1;
392
393                 tmp_buf = malloc(len);
394                 if (!tmp_buf)
395                         return -1;
396
397                 if (len == 1) {
398                         tmp_data.u8 = hex_value;
399                         hex_ptr = &tmp_data.u8;
400                 } else if (len == 2) {
401                         tmp_data.u16 = hex_value;
402                         hex_ptr = &tmp_data.u16;
403                 } else if (len == 4) {
404                         tmp_data.u32 = hex_value;
405                         hex_ptr = &tmp_data.u32;
406                 } else {
407                         tmp_data.u64 = hex_value;
408                         hex_ptr = &tmp_data.u64;
409                 }
410                 memcpy(tmp_buf, hex_ptr, len);
411                 value = tmp_buf;
412
413         } else if (!strncmp(data, "=H", 2)) { /* hexadecimal-byte array */
414                 data += 2;
415                 len = strlen(data);
416                 if (len & 0x1) /* not multiple of two */
417                         return -1;
418
419                 len /= 2;
420                 tmp_buf = malloc(len);
421                 if (!tmp_buf)
422                         return -1;
423
424                 if (hex2bin((u8 *)tmp_buf, data, len) < 0) {
425                         printf("Error: illegal hexadecimal string\n");
426                         free(tmp_buf);
427                         return -1;
428                 }
429
430                 value = tmp_buf;
431         } else { /* string */
432                 if (!strncmp(data, "=\"", 2) || !strncmp(data, "=S\"", 3)) {
433                         if (data[1] == '"')
434                                 data += 2;
435                         else
436                                 data += 3;
437                         value = data;
438                         len = strlen(data) - 1;
439                         if (data[len] != '"')
440                                 return -1;
441                 } else {
442                         value = data;
443                         len = strlen(data);
444                 }
445         }
446
447         new_buf = realloc(*bufp, *sizep + len);
448         if (!new_buf)
449                 goto out;
450
451         memcpy(new_buf + *sizep, value, len);
452         *bufp = new_buf;
453         *sizep += len;
454
455 out:
456         free(tmp_buf);
457
458         return 0;
459 }
460
461 /**
462  * do_env_set_efi() - set UEFI variable
463  *
464  * @cmdtp:      Command table
465  * @flag:       Command flag
466  * @argc:       Number of arguments
467  * @argv:       Argument array
468  * Return:      CMD_RET_SUCCESS on success, or CMD_RET_RET_FAILURE
469  *
470  * This function is for "env set -e" or "setenv -e" command:
471  *   => env set -e [-guid guid][-nv][-bs][-rt][-at][-a][-v]
472  *                 [-i address,size] var, or
473  *                 var [value ...]
474  * Encode values specified and set given UEFI variable.
475  * If no value is specified, delete the variable.
476  */
477 int do_env_set_efi(struct cmd_tbl *cmdtp, int flag, int argc,
478                    char *const argv[])
479 {
480         char *var_name, *value, *ep;
481         ulong addr;
482         efi_uintn_t size;
483         efi_guid_t guid;
484         u32 attributes;
485         bool default_guid, verbose, value_on_memory;
486         u16 *var_name16 = NULL, *p;
487         size_t len;
488         efi_status_t ret;
489
490         if (argc == 1)
491                 return CMD_RET_USAGE;
492
493         /* Initialize EFI drivers */
494         ret = efi_init_obj_list();
495         if (ret != EFI_SUCCESS) {
496                 printf("Error: Cannot initialize UEFI sub-system, r = %lu\n",
497                        ret & ~EFI_ERROR_MASK);
498                 return CMD_RET_FAILURE;
499         }
500
501         /*
502          * attributes = EFI_VARIABLE_BOOTSERVICE_ACCESS |
503          *           EFI_VARIABLE_RUNTIME_ACCESS;
504          */
505         value = NULL;
506         size = 0;
507         attributes = 0;
508         guid = efi_global_variable_guid;
509         default_guid = true;
510         verbose = false;
511         value_on_memory = false;
512         for (argc--, argv++; argc > 0 && argv[0][0] == '-'; argc--, argv++) {
513                 if (!strcmp(argv[0], "-guid")) {
514                         if (argc == 1)
515                                 return CMD_RET_USAGE;
516
517                         argc--;
518                         argv++;
519                         if (uuid_str_to_bin(argv[0], guid.b,
520                                             UUID_STR_FORMAT_GUID)) {
521                                 printf("## Guid not specified or in XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX format\n");
522                                 return CMD_RET_FAILURE;
523                         }
524                         default_guid = false;
525                 } else if (!strcmp(argv[0], "-bs")) {
526                         attributes |= EFI_VARIABLE_BOOTSERVICE_ACCESS;
527                 } else if (!strcmp(argv[0], "-rt")) {
528                         attributes |= EFI_VARIABLE_RUNTIME_ACCESS;
529                 } else if (!strcmp(argv[0], "-nv")) {
530                         attributes |= EFI_VARIABLE_NON_VOLATILE;
531                 } else if (!strcmp(argv[0], "-at")) {
532                         attributes |=
533                           EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
534                 } else if (!strcmp(argv[0], "-a")) {
535                         attributes |= EFI_VARIABLE_APPEND_WRITE;
536                 } else if (!strcmp(argv[0], "-i")) {
537                         /* data comes from memory */
538                         if (argc == 1)
539                                 return CMD_RET_USAGE;
540
541                         argc--;
542                         argv++;
543                         addr = simple_strtoul(argv[0], &ep, 16);
544                         if (*ep != ',')
545                                 return CMD_RET_USAGE;
546
547                         /* 0 should be allowed for delete */
548                         size = simple_strtoul(++ep, NULL, 16);
549
550                         value_on_memory = true;
551                 } else if (!strcmp(argv[0], "-v")) {
552                         verbose = true;
553                 } else {
554                         return CMD_RET_USAGE;
555                 }
556         }
557         if (!argc)
558                 return CMD_RET_USAGE;
559
560         var_name = argv[0];
561         if (default_guid) {
562                 if (!strcmp(var_name, "db") || !strcmp(var_name, "dbx") ||
563                     !strcmp(var_name, "dbt"))
564                         guid = efi_guid_image_security_database;
565                 else
566                         guid = efi_global_variable_guid;
567         }
568
569         if (verbose) {
570                 printf("GUID: %s\n", efi_guid_to_str((const efi_guid_t *)
571                                                      &guid));
572                 printf("Attributes: 0x%x\n", attributes);
573         }
574
575         /* for value */
576         if (value_on_memory)
577                 value = map_sysmem(addr, 0);
578         else if (argc > 1)
579                 for (argc--, argv++; argc > 0; argc--, argv++)
580                         if (append_value(&value, &size, argv[0]) < 0) {
581                                 printf("## Failed to process an argument, %s\n",
582                                        argv[0]);
583                                 ret = CMD_RET_FAILURE;
584                                 goto out;
585                         }
586
587         if (size && verbose) {
588                 printf("Value:\n");
589                 print_hex_dump("    ", DUMP_PREFIX_OFFSET,
590                                16, 1, value, size, true);
591         }
592
593         len = utf8_utf16_strnlen(var_name, strlen(var_name));
594         var_name16 = malloc((len + 1) * 2);
595         if (!var_name16) {
596                 printf("## Out of memory\n");
597                 ret = CMD_RET_FAILURE;
598                 goto out;
599         }
600         p = var_name16;
601         utf8_utf16_strncpy(&p, var_name, len + 1);
602
603         ret = efi_set_variable_int(var_name16, &guid, attributes, size, value,
604                                    true);
605         unmap_sysmem(value);
606         if (ret == EFI_SUCCESS) {
607                 ret = CMD_RET_SUCCESS;
608         } else {
609                 const char *msg;
610
611                 switch (ret) {
612                 case EFI_NOT_FOUND:
613                         msg = " (not found)";
614                         break;
615                 case EFI_WRITE_PROTECTED:
616                         msg = " (read only)";
617                         break;
618                 case EFI_INVALID_PARAMETER:
619                         msg = " (invalid parameter)";
620                         break;
621                 case EFI_SECURITY_VIOLATION:
622                         msg = " (validation failed)";
623                         break;
624                 case EFI_OUT_OF_RESOURCES:
625                         msg = " (out of memory)";
626                         break;
627                 default:
628                         msg = "";
629                         break;
630                 }
631                 printf("## Failed to set EFI variable%s\n", msg);
632                 ret = CMD_RET_FAILURE;
633         }
634 out:
635         if (value_on_memory)
636                 unmap_sysmem(value);
637         else
638                 free(value);
639         free(var_name16);
640
641         return ret;
642 }