Merge tag 'arc-fixes-for-2020.01-rc2' of https://gitlab.denx.de/u-boot/custodians...
[oweals/u-boot.git] / lib / efi_loader / efi_variable.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  *  EFI utils
4  *
5  *  Copyright (c) 2017 Rob Clark
6  */
7
8 #include <common.h>
9 #include <efi_loader.h>
10 #include <env_internal.h>
11 #include <hexdump.h>
12 #include <malloc.h>
13 #include <search.h>
14
15 #define READ_ONLY BIT(31)
16
17 /*
18  * Mapping between EFI variables and u-boot variables:
19  *
20  *   efi_$guid_$varname = {attributes}(type)value
21  *
22  * For example:
23  *
24  *   efi_8be4df61-93ca-11d2-aa0d-00e098032b8c_OsIndicationsSupported=
25  *      "{ro,boot,run}(blob)0000000000000000"
26  *   efi_8be4df61-93ca-11d2-aa0d-00e098032b8c_BootOrder=
27  *      "(blob)00010000"
28  *
29  * The attributes are a comma separated list of these possible
30  * attributes:
31  *
32  *   + ro   - read-only
33  *   + boot - boot-services access
34  *   + run  - runtime access
35  *
36  * NOTE: with current implementation, no variables are available after
37  * ExitBootServices, and all are persisted (if possible).
38  *
39  * If not specified, the attributes default to "{boot}".
40  *
41  * The required type is one of:
42  *
43  *   + utf8 - raw utf8 string
44  *   + blob - arbitrary length hex string
45  *
46  * Maybe a utf16 type would be useful to for a string value to be auto
47  * converted to utf16?
48  */
49
50 #define PREFIX_LEN (strlen("efi_xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx_"))
51
52 /**
53  * efi_to_native() - convert the UEFI variable name and vendor GUID to U-Boot
54  *                   variable name
55  *
56  * The U-Boot variable name is a concatenation of prefix 'efi', the hexstring
57  * encoded vendor GUID, and the UTF-8 encoded UEFI variable name separated by
58  * underscores, e.g. 'efi_8be4df61-93ca-11d2-aa0d-00e098032b8c_BootOrder'.
59  *
60  * @native:             pointer to pointer to U-Boot variable name
61  * @variable_name:      UEFI variable name
62  * @vendor:             vendor GUID
63  * Return:              status code
64  */
65 static efi_status_t efi_to_native(char **native, const u16 *variable_name,
66                                   const efi_guid_t *vendor)
67 {
68         size_t len;
69         char *pos;
70
71         len = PREFIX_LEN + utf16_utf8_strlen(variable_name) + 1;
72         *native = malloc(len);
73         if (!*native)
74                 return EFI_OUT_OF_RESOURCES;
75
76         pos = *native;
77         pos += sprintf(pos, "efi_%pUl_", vendor);
78         utf16_utf8_strcpy(&pos, variable_name);
79
80         return EFI_SUCCESS;
81 }
82
83 /**
84  * prefix() - skip over prefix
85  *
86  * Skip over a prefix string.
87  *
88  * @str:        string with prefix
89  * @prefix:     prefix string
90  * Return:      string without prefix, or NULL if prefix not found
91  */
92 static const char *prefix(const char *str, const char *prefix)
93 {
94         size_t n = strlen(prefix);
95         if (!strncmp(prefix, str, n))
96                 return str + n;
97         return NULL;
98 }
99
100 /**
101  * parse_attr() - decode attributes part of variable value
102  *
103  * Convert the string encoded attributes of a UEFI variable to a bit mask.
104  * TODO: Several attributes are not supported.
105  *
106  * @str:        value of U-Boot variable
107  * @attrp:      pointer to UEFI attributes
108  * Return:      pointer to remainder of U-Boot variable value
109  */
110 static const char *parse_attr(const char *str, u32 *attrp)
111 {
112         u32 attr = 0;
113         char sep = '{';
114
115         if (*str != '{') {
116                 *attrp = EFI_VARIABLE_BOOTSERVICE_ACCESS;
117                 return str;
118         }
119
120         while (*str == sep) {
121                 const char *s;
122
123                 str++;
124
125                 if ((s = prefix(str, "ro"))) {
126                         attr |= READ_ONLY;
127                 } else if ((s = prefix(str, "nv"))) {
128                         attr |= EFI_VARIABLE_NON_VOLATILE;
129                 } else if ((s = prefix(str, "boot"))) {
130                         attr |= EFI_VARIABLE_BOOTSERVICE_ACCESS;
131                 } else if ((s = prefix(str, "run"))) {
132                         attr |= EFI_VARIABLE_RUNTIME_ACCESS;
133                 } else {
134                         printf("invalid attribute: %s\n", str);
135                         break;
136                 }
137
138                 str = s;
139                 sep = ',';
140         }
141
142         str++;
143
144         *attrp = attr;
145
146         return str;
147 }
148
149 /**
150  * efi_get_variable() - retrieve value of a UEFI variable
151  *
152  * This function implements the GetVariable runtime service.
153  *
154  * See the Unified Extensible Firmware Interface (UEFI) specification for
155  * details.
156  *
157  * @variable_name:      name of the variable
158  * @vendor:             vendor GUID
159  * @attributes:         attributes of the variable
160  * @data_size:          size of the buffer to which the variable value is copied
161  * @data:               buffer to which the variable value is copied
162  * Return:              status code
163  */
164 efi_status_t EFIAPI efi_get_variable(u16 *variable_name,
165                                      const efi_guid_t *vendor, u32 *attributes,
166                                      efi_uintn_t *data_size, void *data)
167 {
168         char *native_name;
169         efi_status_t ret;
170         unsigned long in_size;
171         const char *val, *s;
172         u32 attr;
173
174         EFI_ENTRY("\"%ls\" %pUl %p %p %p", variable_name, vendor, attributes,
175                   data_size, data);
176
177         if (!variable_name || !vendor || !data_size)
178                 return EFI_EXIT(EFI_INVALID_PARAMETER);
179
180         ret = efi_to_native(&native_name, variable_name, vendor);
181         if (ret)
182                 return EFI_EXIT(ret);
183
184         EFI_PRINT("get '%s'\n", native_name);
185
186         val = env_get(native_name);
187         free(native_name);
188         if (!val)
189                 return EFI_EXIT(EFI_NOT_FOUND);
190
191         val = parse_attr(val, &attr);
192
193         in_size = *data_size;
194
195         if ((s = prefix(val, "(blob)"))) {
196                 size_t len = strlen(s);
197
198                 /* number of hexadecimal digits must be even */
199                 if (len & 1)
200                         return EFI_EXIT(EFI_DEVICE_ERROR);
201
202                 /* two characters per byte: */
203                 len /= 2;
204                 *data_size = len;
205
206                 if (in_size < len) {
207                         ret = EFI_BUFFER_TOO_SMALL;
208                         goto out;
209                 }
210
211                 if (!data)
212                         return EFI_EXIT(EFI_INVALID_PARAMETER);
213
214                 if (hex2bin(data, s, len))
215                         return EFI_EXIT(EFI_DEVICE_ERROR);
216
217                 EFI_PRINT("got value: \"%s\"\n", s);
218         } else if ((s = prefix(val, "(utf8)"))) {
219                 unsigned len = strlen(s) + 1;
220
221                 *data_size = len;
222
223                 if (in_size < len) {
224                         ret = EFI_BUFFER_TOO_SMALL;
225                         goto out;
226                 }
227
228                 if (!data)
229                         return EFI_EXIT(EFI_INVALID_PARAMETER);
230
231                 memcpy(data, s, len);
232                 ((char *)data)[len] = '\0';
233
234                 EFI_PRINT("got value: \"%s\"\n", (char *)data);
235         } else {
236                 EFI_PRINT("invalid value: '%s'\n", val);
237                 return EFI_EXIT(EFI_DEVICE_ERROR);
238         }
239
240 out:
241         if (attributes)
242                 *attributes = attr & EFI_VARIABLE_MASK;
243
244         return EFI_EXIT(ret);
245 }
246
247 static char *efi_variables_list;
248 static char *efi_cur_variable;
249
250 /**
251  * parse_uboot_variable() - parse a u-boot variable and get uefi-related
252  *                          information
253  * @variable:           whole data of u-boot variable (ie. name=value)
254  * @variable_name_size: size of variable_name buffer in byte
255  * @variable_name:      name of uefi variable in u16, null-terminated
256  * @vendor:             vendor's guid
257  * @attributes:         attributes
258  *
259  * A uefi variable is encoded into a u-boot variable as described above.
260  * This function parses such a u-boot variable and retrieve uefi-related
261  * information into respective parameters. In return, variable_name_size
262  * is the size of variable name including NULL.
263  *
264  * Return:              EFI_SUCCESS if parsing is OK, EFI_NOT_FOUND when
265  *                      the entire variable list has been returned,
266  *                      otherwise non-zero status code
267  */
268 static efi_status_t parse_uboot_variable(char *variable,
269                                          efi_uintn_t *variable_name_size,
270                                          u16 *variable_name,
271                                          const efi_guid_t *vendor,
272                                          u32 *attributes)
273 {
274         char *guid, *name, *end, c;
275         unsigned long name_len;
276         u16 *p;
277
278         guid = strchr(variable, '_');
279         if (!guid)
280                 return EFI_INVALID_PARAMETER;
281         guid++;
282         name = strchr(guid, '_');
283         if (!name)
284                 return EFI_INVALID_PARAMETER;
285         name++;
286         end = strchr(name, '=');
287         if (!end)
288                 return EFI_INVALID_PARAMETER;
289
290         name_len = end - name;
291         if (*variable_name_size < (name_len + 1)) {
292                 *variable_name_size = name_len + 1;
293                 return EFI_BUFFER_TOO_SMALL;
294         }
295         end++; /* point to value */
296
297         /* variable name */
298         p = variable_name;
299         utf8_utf16_strncpy(&p, name, name_len);
300         variable_name[name_len] = 0;
301         *variable_name_size = name_len + 1;
302
303         /* guid */
304         c = *(name - 1);
305         *(name - 1) = '\0'; /* guid need be null-terminated here */
306         uuid_str_to_bin(guid, (unsigned char *)vendor, UUID_STR_FORMAT_GUID);
307         *(name - 1) = c;
308
309         /* attributes */
310         parse_attr(end, attributes);
311
312         return EFI_SUCCESS;
313 }
314
315 /**
316  * efi_get_next_variable_name() - enumerate the current variable names
317  *
318  * @variable_name_size: size of variable_name buffer in byte
319  * @variable_name:      name of uefi variable's name in u16
320  * @vendor:             vendor's guid
321  *
322  * This function implements the GetNextVariableName service.
323  *
324  * See the Unified Extensible Firmware Interface (UEFI) specification for
325  * details.
326  *
327  * Return: status code
328  */
329 efi_status_t EFIAPI efi_get_next_variable_name(efi_uintn_t *variable_name_size,
330                                                u16 *variable_name,
331                                                const efi_guid_t *vendor)
332 {
333         char *native_name, *variable;
334         ssize_t name_len, list_len;
335         char regex[256];
336         char * const regexlist[] = {regex};
337         u32 attributes;
338         int i;
339         efi_status_t ret;
340
341         EFI_ENTRY("%p \"%ls\" %pUl", variable_name_size, variable_name, vendor);
342
343         if (!variable_name_size || !variable_name || !vendor)
344                 return EFI_EXIT(EFI_INVALID_PARAMETER);
345
346         if (variable_name[0]) {
347                 /* check null-terminated string */
348                 for (i = 0; i < *variable_name_size; i++)
349                         if (!variable_name[i])
350                                 break;
351                 if (i >= *variable_name_size)
352                         return EFI_EXIT(EFI_INVALID_PARAMETER);
353
354                 /* search for the last-returned variable */
355                 ret = efi_to_native(&native_name, variable_name, vendor);
356                 if (ret)
357                         return EFI_EXIT(ret);
358
359                 name_len = strlen(native_name);
360                 for (variable = efi_variables_list; variable && *variable;) {
361                         if (!strncmp(variable, native_name, name_len) &&
362                             variable[name_len] == '=')
363                                 break;
364
365                         variable = strchr(variable, '\n');
366                         if (variable)
367                                 variable++;
368                 }
369
370                 free(native_name);
371                 if (!(variable && *variable))
372                         return EFI_EXIT(EFI_INVALID_PARAMETER);
373
374                 /* next variable */
375                 variable = strchr(variable, '\n');
376                 if (variable)
377                         variable++;
378                 if (!(variable && *variable))
379                         return EFI_EXIT(EFI_NOT_FOUND);
380         } else {
381                 /*
382                  *new search: free a list used in the previous search
383                  */
384                 free(efi_variables_list);
385                 efi_variables_list = NULL;
386                 efi_cur_variable = NULL;
387
388                 snprintf(regex, 256, "efi_.*-.*-.*-.*-.*_.*");
389                 list_len = hexport_r(&env_htab, '\n',
390                                      H_MATCH_REGEX | H_MATCH_KEY,
391                                      &efi_variables_list, 0, 1, regexlist);
392                 /* 1 indicates that no match was found */
393                 if (list_len <= 1)
394                         return EFI_EXIT(EFI_NOT_FOUND);
395
396                 variable = efi_variables_list;
397         }
398
399         ret = parse_uboot_variable(variable, variable_name_size, variable_name,
400                                    vendor, &attributes);
401
402         return EFI_EXIT(ret);
403 }
404
405 /**
406  * efi_set_variable() - set value of a UEFI variable
407  *
408  * This function implements the SetVariable runtime service.
409  *
410  * See the Unified Extensible Firmware Interface (UEFI) specification for
411  * details.
412  *
413  * @variable_name:      name of the variable
414  * @vendor:             vendor GUID
415  * @attributes:         attributes of the variable
416  * @data_size:          size of the buffer with the variable value
417  * @data:               buffer with the variable value
418  * Return:              status code
419  */
420 efi_status_t EFIAPI efi_set_variable(u16 *variable_name,
421                                      const efi_guid_t *vendor, u32 attributes,
422                                      efi_uintn_t data_size, const void *data)
423 {
424         char *native_name = NULL, *val = NULL, *s;
425         const char *old_val;
426         size_t old_size;
427         efi_status_t ret = EFI_SUCCESS;
428         u32 attr;
429
430         EFI_ENTRY("\"%ls\" %pUl %x %zu %p", variable_name, vendor, attributes,
431                   data_size, data);
432
433         if (!variable_name || !*variable_name || !vendor ||
434             ((attributes & EFI_VARIABLE_RUNTIME_ACCESS) &&
435              !(attributes & EFI_VARIABLE_BOOTSERVICE_ACCESS))) {
436                 ret = EFI_INVALID_PARAMETER;
437                 goto out;
438         }
439
440         ret = efi_to_native(&native_name, variable_name, vendor);
441         if (ret)
442                 goto out;
443
444         old_val = env_get(native_name);
445         if (old_val) {
446                 old_val = parse_attr(old_val, &attr);
447
448                 /* check read-only first */
449                 if (attr & READ_ONLY) {
450                         ret = EFI_WRITE_PROTECTED;
451                         goto out;
452                 }
453
454                 if ((data_size == 0 &&
455                      !(attributes & EFI_VARIABLE_APPEND_WRITE)) ||
456                     !attributes) {
457                         /* delete the variable: */
458                         env_set(native_name, NULL);
459                         ret = EFI_SUCCESS;
460                         goto out;
461                 }
462
463                 /* attributes won't be changed */
464                 if (attr != (attributes & ~EFI_VARIABLE_APPEND_WRITE)) {
465                         ret = EFI_INVALID_PARAMETER;
466                         goto out;
467                 }
468
469                 if (attributes & EFI_VARIABLE_APPEND_WRITE) {
470                         if (!prefix(old_val, "(blob)")) {
471                                 ret = EFI_DEVICE_ERROR;
472                                 goto out;
473                         }
474                         old_size = strlen(old_val);
475                 } else {
476                         old_size = 0;
477                 }
478         } else {
479                 if (data_size == 0 || !attributes ||
480                     (attributes & EFI_VARIABLE_APPEND_WRITE)) {
481                         /*
482                          * Trying to delete or to update a non-existent
483                          * variable.
484                          */
485                         ret = EFI_NOT_FOUND;
486                         goto out;
487                 }
488
489                 old_size = 0;
490         }
491
492         val = malloc(old_size + 2 * data_size
493                      + strlen("{ro,run,boot,nv}(blob)") + 1);
494         if (!val) {
495                 ret = EFI_OUT_OF_RESOURCES;
496                 goto out;
497         }
498
499         s = val;
500
501         /* store attributes */
502         attributes &= (EFI_VARIABLE_NON_VOLATILE |
503                        EFI_VARIABLE_BOOTSERVICE_ACCESS |
504                        EFI_VARIABLE_RUNTIME_ACCESS);
505         s += sprintf(s, "{");
506         while (attributes) {
507                 u32 attr = 1 << (ffs(attributes) - 1);
508
509                 if (attr == EFI_VARIABLE_NON_VOLATILE)
510                         s += sprintf(s, "nv");
511                 else if (attr == EFI_VARIABLE_BOOTSERVICE_ACCESS)
512                         s += sprintf(s, "boot");
513                 else if (attr == EFI_VARIABLE_RUNTIME_ACCESS)
514                         s += sprintf(s, "run");
515
516                 attributes &= ~attr;
517                 if (attributes)
518                         s += sprintf(s, ",");
519         }
520         s += sprintf(s, "}");
521
522         if (old_size)
523                 /* APPEND_WRITE */
524                 s += sprintf(s, old_val);
525         else
526                 s += sprintf(s, "(blob)");
527
528         /* store payload: */
529         s = bin2hex(s, data, data_size);
530         *s = '\0';
531
532         EFI_PRINT("setting: %s=%s\n", native_name, val);
533
534         if (env_set(native_name, val))
535                 ret = EFI_DEVICE_ERROR;
536
537 out:
538         free(native_name);
539         free(val);
540
541         return EFI_EXIT(ret);
542 }
543
544 /**
545  * efi_query_variable_info() - get information about EFI variables
546  *
547  * This function implements the QueryVariableInfo() runtime service.
548  *
549  * See the Unified Extensible Firmware Interface (UEFI) specification for
550  * details.
551  *
552  * @attributes:                         bitmask to select variables to be
553  *                                      queried
554  * @maximum_variable_storage_size:      maximum size of storage area for the
555  *                                      selected variable types
556  * @remaining_variable_storage_size:    remaining size of storage are for the
557  *                                      selected variable types
558  * @maximum_variable_size:              maximum size of a variable of the
559  *                                      selected type
560  * Returns:                             status code
561  */
562 efi_status_t __efi_runtime EFIAPI efi_query_variable_info(
563                         u32 attributes,
564                         u64 *maximum_variable_storage_size,
565                         u64 *remaining_variable_storage_size,
566                         u64 *maximum_variable_size)
567 {
568         return EFI_UNSUPPORTED;
569 }
570
571 /**
572  * efi_get_variable_runtime() - runtime implementation of GetVariable()
573  *
574  * @variable_name:      name of the variable
575  * @vendor:             vendor GUID
576  * @attributes:         attributes of the variable
577  * @data_size:          size of the buffer to which the variable value is copied
578  * @data:               buffer to which the variable value is copied
579  * Return:              status code
580  */
581 static efi_status_t __efi_runtime EFIAPI
582 efi_get_variable_runtime(u16 *variable_name, const efi_guid_t *vendor,
583                          u32 *attributes, efi_uintn_t *data_size, void *data)
584 {
585         return EFI_UNSUPPORTED;
586 }
587
588 /**
589  * efi_get_next_variable_name_runtime() - runtime implementation of
590  *                                        GetNextVariable()
591  *
592  * @variable_name_size: size of variable_name buffer in byte
593  * @variable_name:      name of uefi variable's name in u16
594  * @vendor:             vendor's guid
595  * Return: status code
596  */
597 static efi_status_t __efi_runtime EFIAPI
598 efi_get_next_variable_name_runtime(efi_uintn_t *variable_name_size,
599                                    u16 *variable_name, const efi_guid_t *vendor)
600 {
601         return EFI_UNSUPPORTED;
602 }
603
604 /**
605  * efi_set_variable_runtime() - runtime implementation of SetVariable()
606  *
607  * @variable_name:      name of the variable
608  * @vendor:             vendor GUID
609  * @attributes:         attributes of the variable
610  * @data_size:          size of the buffer with the variable value
611  * @data:               buffer with the variable value
612  * Return:              status code
613  */
614 static efi_status_t __efi_runtime EFIAPI
615 efi_set_variable_runtime(u16 *variable_name, const efi_guid_t *vendor,
616                          u32 attributes, efi_uintn_t data_size,
617                          const void *data)
618 {
619         return EFI_UNSUPPORTED;
620 }
621
622 /**
623  * efi_variables_boot_exit_notify() - notify ExitBootServices() is called
624  */
625 void efi_variables_boot_exit_notify(void)
626 {
627         efi_runtime_services.get_variable = efi_get_variable_runtime;
628         efi_runtime_services.get_next_variable_name =
629                                 efi_get_next_variable_name_runtime;
630         efi_runtime_services.set_variable = efi_set_variable_runtime;
631         efi_update_table_header_crc32(&efi_runtime_services.hdr);
632 }
633
634 /**
635  * efi_init_variables() - initialize variable services
636  *
637  * Return:      status code
638  */
639 efi_status_t efi_init_variables(void)
640 {
641         return EFI_SUCCESS;
642 }