1f739fcd8STom Rini // SPDX-License-Identifier: GPL-2.0+
2ad644e7cSRob Clark /*
3ad644e7cSRob Clark * EFI utils
4ad644e7cSRob Clark *
5ad644e7cSRob Clark * Copyright (c) 2017 Rob Clark
6ad644e7cSRob Clark */
7ad644e7cSRob Clark
8ad644e7cSRob Clark #include <malloc.h>
9ad644e7cSRob Clark #include <charset.h>
10ad644e7cSRob Clark #include <efi_loader.h>
116e37fa22SHeinrich Schuchardt #include <hexdump.h>
12d99a87f8SAKASHI Takahiro #include <environment.h>
13d99a87f8SAKASHI Takahiro #include <search.h>
14d99a87f8SAKASHI Takahiro #include <uuid.h>
15ad644e7cSRob Clark
16ad644e7cSRob Clark #define READ_ONLY BIT(31)
17ad644e7cSRob Clark
18ad644e7cSRob Clark /*
19ad644e7cSRob Clark * Mapping between EFI variables and u-boot variables:
20ad644e7cSRob Clark *
21ad644e7cSRob Clark * efi_$guid_$varname = {attributes}(type)value
22ad644e7cSRob Clark *
23ad644e7cSRob Clark * For example:
24ad644e7cSRob Clark *
25ad644e7cSRob Clark * efi_8be4df61-93ca-11d2-aa0d-00e098032b8c_OsIndicationsSupported=
26ad644e7cSRob Clark * "{ro,boot,run}(blob)0000000000000000"
27ad644e7cSRob Clark * efi_8be4df61-93ca-11d2-aa0d-00e098032b8c_BootOrder=
28ad644e7cSRob Clark * "(blob)00010000"
29ad644e7cSRob Clark *
30ad644e7cSRob Clark * The attributes are a comma separated list of these possible
31ad644e7cSRob Clark * attributes:
32ad644e7cSRob Clark *
33ad644e7cSRob Clark * + ro - read-only
34ad644e7cSRob Clark * + boot - boot-services access
35ad644e7cSRob Clark * + run - runtime access
36ad644e7cSRob Clark *
37ad644e7cSRob Clark * NOTE: with current implementation, no variables are available after
38ad644e7cSRob Clark * ExitBootServices, and all are persisted (if possible).
39ad644e7cSRob Clark *
40ad644e7cSRob Clark * If not specified, the attributes default to "{boot}".
41ad644e7cSRob Clark *
42ad644e7cSRob Clark * The required type is one of:
43ad644e7cSRob Clark *
44ad644e7cSRob Clark * + utf8 - raw utf8 string
45ad644e7cSRob Clark * + blob - arbitrary length hex string
46ad644e7cSRob Clark *
47ad644e7cSRob Clark * Maybe a utf16 type would be useful to for a string value to be auto
48ad644e7cSRob Clark * converted to utf16?
49ad644e7cSRob Clark */
50ad644e7cSRob Clark
51506dc52dSHeinrich Schuchardt #define PREFIX_LEN (strlen("efi_xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx_"))
52ad644e7cSRob Clark
5377d4d396SHeinrich Schuchardt /**
5477d4d396SHeinrich Schuchardt * efi_to_native() - convert the UEFI variable name and vendor GUID to U-Boot
5577d4d396SHeinrich Schuchardt * variable name
5677d4d396SHeinrich Schuchardt *
5777d4d396SHeinrich Schuchardt * The U-Boot variable name is a concatenation of prefix 'efi', the hexstring
5877d4d396SHeinrich Schuchardt * encoded vendor GUID, and the UTF-8 encoded UEFI variable name separated by
5977d4d396SHeinrich Schuchardt * underscores, e.g. 'efi_8be4df61-93ca-11d2-aa0d-00e098032b8c_BootOrder'.
6077d4d396SHeinrich Schuchardt *
6177d4d396SHeinrich Schuchardt * @native: pointer to pointer to U-Boot variable name
6277d4d396SHeinrich Schuchardt * @variable_name: UEFI variable name
6377d4d396SHeinrich Schuchardt * @vendor: vendor GUID
6477d4d396SHeinrich Schuchardt * Return: status code
6577d4d396SHeinrich Schuchardt */
efi_to_native(char ** native,const u16 * variable_name,const efi_guid_t * vendor)66dcdb64f7SHeinrich Schuchardt static efi_status_t efi_to_native(char **native, const u16 *variable_name,
670bda81bfSHeinrich Schuchardt const efi_guid_t *vendor)
68ad644e7cSRob Clark {
69ad644e7cSRob Clark size_t len;
70dcdb64f7SHeinrich Schuchardt char *pos;
71ad644e7cSRob Clark
72dcdb64f7SHeinrich Schuchardt len = PREFIX_LEN + utf16_utf8_strlen(variable_name) + 1;
73dcdb64f7SHeinrich Schuchardt *native = malloc(len);
74dcdb64f7SHeinrich Schuchardt if (!*native)
75dcdb64f7SHeinrich Schuchardt return EFI_OUT_OF_RESOURCES;
76ad644e7cSRob Clark
77dcdb64f7SHeinrich Schuchardt pos = *native;
78dcdb64f7SHeinrich Schuchardt pos += sprintf(pos, "efi_%pUl_", vendor);
79dcdb64f7SHeinrich Schuchardt utf16_utf8_strcpy(&pos, variable_name);
80ad644e7cSRob Clark
81ad644e7cSRob Clark return EFI_SUCCESS;
82ad644e7cSRob Clark }
83ad644e7cSRob Clark
8477d4d396SHeinrich Schuchardt /**
8577d4d396SHeinrich Schuchardt * prefix() - skip over prefix
8677d4d396SHeinrich Schuchardt *
8777d4d396SHeinrich Schuchardt * Skip over a prefix string.
8877d4d396SHeinrich Schuchardt *
8977d4d396SHeinrich Schuchardt * @str: string with prefix
9077d4d396SHeinrich Schuchardt * @prefix: prefix string
9177d4d396SHeinrich Schuchardt * Return: string without prefix, or NULL if prefix not found
9277d4d396SHeinrich Schuchardt */
prefix(const char * str,const char * prefix)93ad644e7cSRob Clark static const char *prefix(const char *str, const char *prefix)
94ad644e7cSRob Clark {
95ad644e7cSRob Clark size_t n = strlen(prefix);
96ad644e7cSRob Clark if (!strncmp(prefix, str, n))
97ad644e7cSRob Clark return str + n;
98ad644e7cSRob Clark return NULL;
99ad644e7cSRob Clark }
100ad644e7cSRob Clark
10177d4d396SHeinrich Schuchardt /**
10277d4d396SHeinrich Schuchardt * parse_attr() - decode attributes part of variable value
10377d4d396SHeinrich Schuchardt *
10477d4d396SHeinrich Schuchardt * Convert the string encoded attributes of a UEFI variable to a bit mask.
10577d4d396SHeinrich Schuchardt * TODO: Several attributes are not supported.
10677d4d396SHeinrich Schuchardt *
10777d4d396SHeinrich Schuchardt * @str: value of U-Boot variable
10877d4d396SHeinrich Schuchardt * @attrp: pointer to UEFI attributes
10977d4d396SHeinrich Schuchardt * Return: pointer to remainder of U-Boot variable value
11077d4d396SHeinrich Schuchardt */
parse_attr(const char * str,u32 * attrp)111ad644e7cSRob Clark static const char *parse_attr(const char *str, u32 *attrp)
112ad644e7cSRob Clark {
113ad644e7cSRob Clark u32 attr = 0;
114ad644e7cSRob Clark char sep = '{';
115ad644e7cSRob Clark
116ad644e7cSRob Clark if (*str != '{') {
117ad644e7cSRob Clark *attrp = EFI_VARIABLE_BOOTSERVICE_ACCESS;
118ad644e7cSRob Clark return str;
119ad644e7cSRob Clark }
120ad644e7cSRob Clark
121ad644e7cSRob Clark while (*str == sep) {
122ad644e7cSRob Clark const char *s;
123ad644e7cSRob Clark
124ad644e7cSRob Clark str++;
125ad644e7cSRob Clark
126ad644e7cSRob Clark if ((s = prefix(str, "ro"))) {
127ad644e7cSRob Clark attr |= READ_ONLY;
128ad644e7cSRob Clark } else if ((s = prefix(str, "boot"))) {
129ad644e7cSRob Clark attr |= EFI_VARIABLE_BOOTSERVICE_ACCESS;
130ad644e7cSRob Clark } else if ((s = prefix(str, "run"))) {
131ad644e7cSRob Clark attr |= EFI_VARIABLE_RUNTIME_ACCESS;
132ad644e7cSRob Clark } else {
133ad644e7cSRob Clark printf("invalid attribute: %s\n", str);
134ad644e7cSRob Clark break;
135ad644e7cSRob Clark }
136ad644e7cSRob Clark
137ad644e7cSRob Clark str = s;
138ad644e7cSRob Clark sep = ',';
139ad644e7cSRob Clark }
140ad644e7cSRob Clark
141ad644e7cSRob Clark str++;
142ad644e7cSRob Clark
143ad644e7cSRob Clark *attrp = attr;
144ad644e7cSRob Clark
145ad644e7cSRob Clark return str;
146ad644e7cSRob Clark }
147ad644e7cSRob Clark
14877d4d396SHeinrich Schuchardt /**
14977d4d396SHeinrich Schuchardt * efi_efi_get_variable() - retrieve value of a UEFI variable
15077d4d396SHeinrich Schuchardt *
15177d4d396SHeinrich Schuchardt * This function implements the GetVariable runtime service.
15277d4d396SHeinrich Schuchardt *
15377d4d396SHeinrich Schuchardt * See the Unified Extensible Firmware Interface (UEFI) specification for
15477d4d396SHeinrich Schuchardt * details.
15577d4d396SHeinrich Schuchardt *
15677d4d396SHeinrich Schuchardt * @variable_name: name of the variable
15777d4d396SHeinrich Schuchardt * @vendor: vendor GUID
15877d4d396SHeinrich Schuchardt * @attributes: attributes of the variable
15977d4d396SHeinrich Schuchardt * @data_size: size of the buffer to which the variable value is copied
16077d4d396SHeinrich Schuchardt * @data: buffer to which the variable value is copied
16177d4d396SHeinrich Schuchardt * Return: status code
16277d4d396SHeinrich Schuchardt */
efi_get_variable(u16 * variable_name,const efi_guid_t * vendor,u32 * attributes,efi_uintn_t * data_size,void * data)1630bda81bfSHeinrich Schuchardt efi_status_t EFIAPI efi_get_variable(u16 *variable_name,
1640bda81bfSHeinrich Schuchardt const efi_guid_t *vendor, u32 *attributes,
1650bda81bfSHeinrich Schuchardt efi_uintn_t *data_size, void *data)
166ad644e7cSRob Clark {
167dcdb64f7SHeinrich Schuchardt char *native_name;
168ad644e7cSRob Clark efi_status_t ret;
169ad644e7cSRob Clark unsigned long in_size;
170ad644e7cSRob Clark const char *val, *s;
171ad644e7cSRob Clark u32 attr;
172ad644e7cSRob Clark
173778e6af8SRob Clark EFI_ENTRY("\"%ls\" %pUl %p %p %p", variable_name, vendor, attributes,
174ad644e7cSRob Clark data_size, data);
175ad644e7cSRob Clark
176ad644e7cSRob Clark if (!variable_name || !vendor || !data_size)
177ad644e7cSRob Clark return EFI_EXIT(EFI_INVALID_PARAMETER);
178ad644e7cSRob Clark
179dcdb64f7SHeinrich Schuchardt ret = efi_to_native(&native_name, variable_name, vendor);
180ad644e7cSRob Clark if (ret)
181ad644e7cSRob Clark return EFI_EXIT(ret);
182ad644e7cSRob Clark
183ad644e7cSRob Clark debug("%s: get '%s'\n", __func__, native_name);
184ad644e7cSRob Clark
185ad644e7cSRob Clark val = env_get(native_name);
186dcdb64f7SHeinrich Schuchardt free(native_name);
187ad644e7cSRob Clark if (!val)
188ad644e7cSRob Clark return EFI_EXIT(EFI_NOT_FOUND);
189ad644e7cSRob Clark
190ad644e7cSRob Clark val = parse_attr(val, &attr);
191ad644e7cSRob Clark
192ad644e7cSRob Clark in_size = *data_size;
193ad644e7cSRob Clark
194ad644e7cSRob Clark if ((s = prefix(val, "(blob)"))) {
1956e37fa22SHeinrich Schuchardt size_t len = strlen(s);
196ad644e7cSRob Clark
197d73c8bc0SIvan Gorinov /* number of hexadecimal digits must be even */
198d73c8bc0SIvan Gorinov if (len & 1)
199d73c8bc0SIvan Gorinov return EFI_EXIT(EFI_DEVICE_ERROR);
200d73c8bc0SIvan Gorinov
201ad644e7cSRob Clark /* two characters per byte: */
202d73c8bc0SIvan Gorinov len /= 2;
203ad644e7cSRob Clark *data_size = len;
204ad644e7cSRob Clark
205ad644e7cSRob Clark if (in_size < len)
206ad644e7cSRob Clark return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
207ad644e7cSRob Clark
208ad644e7cSRob Clark if (!data)
209ad644e7cSRob Clark return EFI_EXIT(EFI_INVALID_PARAMETER);
210ad644e7cSRob Clark
2116e37fa22SHeinrich Schuchardt if (hex2bin(data, s, len))
212ad644e7cSRob Clark return EFI_EXIT(EFI_DEVICE_ERROR);
213ad644e7cSRob Clark
214ad644e7cSRob Clark debug("%s: got value: \"%s\"\n", __func__, s);
215ad644e7cSRob Clark } else if ((s = prefix(val, "(utf8)"))) {
216ad644e7cSRob Clark unsigned len = strlen(s) + 1;
217ad644e7cSRob Clark
218ad644e7cSRob Clark *data_size = len;
219ad644e7cSRob Clark
220ad644e7cSRob Clark if (in_size < len)
221ad644e7cSRob Clark return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
222ad644e7cSRob Clark
223ad644e7cSRob Clark if (!data)
224ad644e7cSRob Clark return EFI_EXIT(EFI_INVALID_PARAMETER);
225ad644e7cSRob Clark
226ad644e7cSRob Clark memcpy(data, s, len);
227ad644e7cSRob Clark ((char *)data)[len] = '\0';
228ad644e7cSRob Clark
229ad644e7cSRob Clark debug("%s: got value: \"%s\"\n", __func__, (char *)data);
230ad644e7cSRob Clark } else {
231ad644e7cSRob Clark debug("%s: invalid value: '%s'\n", __func__, val);
232ad644e7cSRob Clark return EFI_EXIT(EFI_DEVICE_ERROR);
233ad644e7cSRob Clark }
234ad644e7cSRob Clark
235ad644e7cSRob Clark if (attributes)
236ad644e7cSRob Clark *attributes = attr & EFI_VARIABLE_MASK;
237ad644e7cSRob Clark
238ad644e7cSRob Clark return EFI_EXIT(EFI_SUCCESS);
239ad644e7cSRob Clark }
240ad644e7cSRob Clark
241d99a87f8SAKASHI Takahiro static char *efi_variables_list;
242d99a87f8SAKASHI Takahiro static char *efi_cur_variable;
243d99a87f8SAKASHI Takahiro
24477d4d396SHeinrich Schuchardt /**
245d99a87f8SAKASHI Takahiro * parse_uboot_variable() - parse a u-boot variable and get uefi-related
246d99a87f8SAKASHI Takahiro * information
247d99a87f8SAKASHI Takahiro * @variable: whole data of u-boot variable (ie. name=value)
248d99a87f8SAKASHI Takahiro * @variable_name_size: size of variable_name buffer in byte
249d99a87f8SAKASHI Takahiro * @variable_name: name of uefi variable in u16, null-terminated
250d99a87f8SAKASHI Takahiro * @vendor: vendor's guid
251d99a87f8SAKASHI Takahiro * @attributes: attributes
25277d4d396SHeinrich Schuchardt *
253d99a87f8SAKASHI Takahiro * A uefi variable is encoded into a u-boot variable as described above.
254d99a87f8SAKASHI Takahiro * This function parses such a u-boot variable and retrieve uefi-related
255d99a87f8SAKASHI Takahiro * information into respective parameters. In return, variable_name_size
256d99a87f8SAKASHI Takahiro * is the size of variable name including NULL.
257d99a87f8SAKASHI Takahiro *
258d99a87f8SAKASHI Takahiro * Return: EFI_SUCCESS if parsing is OK, EFI_NOT_FOUND when
259d99a87f8SAKASHI Takahiro the entire variable list has been returned,
260d99a87f8SAKASHI Takahiro otherwise non-zero status code
261d99a87f8SAKASHI Takahiro */
parse_uboot_variable(char * variable,efi_uintn_t * variable_name_size,u16 * variable_name,const efi_guid_t * vendor,u32 * attributes)262d99a87f8SAKASHI Takahiro static efi_status_t parse_uboot_variable(char *variable,
263d99a87f8SAKASHI Takahiro efi_uintn_t *variable_name_size,
264d99a87f8SAKASHI Takahiro u16 *variable_name,
265d99a87f8SAKASHI Takahiro const efi_guid_t *vendor,
266d99a87f8SAKASHI Takahiro u32 *attributes)
267d99a87f8SAKASHI Takahiro {
268d99a87f8SAKASHI Takahiro char *guid, *name, *end, c;
269d99a87f8SAKASHI Takahiro unsigned long name_len;
270d99a87f8SAKASHI Takahiro u16 *p;
271d99a87f8SAKASHI Takahiro
272d99a87f8SAKASHI Takahiro guid = strchr(variable, '_');
273d99a87f8SAKASHI Takahiro if (!guid)
274d99a87f8SAKASHI Takahiro return EFI_INVALID_PARAMETER;
275d99a87f8SAKASHI Takahiro guid++;
276d99a87f8SAKASHI Takahiro name = strchr(guid, '_');
277d99a87f8SAKASHI Takahiro if (!name)
278d99a87f8SAKASHI Takahiro return EFI_INVALID_PARAMETER;
279d99a87f8SAKASHI Takahiro name++;
280d99a87f8SAKASHI Takahiro end = strchr(name, '=');
281d99a87f8SAKASHI Takahiro if (!end)
282d99a87f8SAKASHI Takahiro return EFI_INVALID_PARAMETER;
283d99a87f8SAKASHI Takahiro
284d99a87f8SAKASHI Takahiro name_len = end - name;
285d99a87f8SAKASHI Takahiro if (*variable_name_size < (name_len + 1)) {
286d99a87f8SAKASHI Takahiro *variable_name_size = name_len + 1;
287d99a87f8SAKASHI Takahiro return EFI_BUFFER_TOO_SMALL;
288d99a87f8SAKASHI Takahiro }
289d99a87f8SAKASHI Takahiro end++; /* point to value */
290d99a87f8SAKASHI Takahiro
291d99a87f8SAKASHI Takahiro /* variable name */
292d99a87f8SAKASHI Takahiro p = variable_name;
293d99a87f8SAKASHI Takahiro utf8_utf16_strncpy(&p, name, name_len);
294d99a87f8SAKASHI Takahiro variable_name[name_len] = 0;
295d99a87f8SAKASHI Takahiro *variable_name_size = name_len + 1;
296d99a87f8SAKASHI Takahiro
297d99a87f8SAKASHI Takahiro /* guid */
298d99a87f8SAKASHI Takahiro c = *(name - 1);
299d99a87f8SAKASHI Takahiro *(name - 1) = '\0'; /* guid need be null-terminated here */
300d99a87f8SAKASHI Takahiro uuid_str_to_bin(guid, (unsigned char *)vendor, UUID_STR_FORMAT_GUID);
301d99a87f8SAKASHI Takahiro *(name - 1) = c;
302d99a87f8SAKASHI Takahiro
303d99a87f8SAKASHI Takahiro /* attributes */
304d99a87f8SAKASHI Takahiro parse_attr(end, attributes);
305d99a87f8SAKASHI Takahiro
306d99a87f8SAKASHI Takahiro return EFI_SUCCESS;
307d99a87f8SAKASHI Takahiro }
308d99a87f8SAKASHI Takahiro
309d99a87f8SAKASHI Takahiro /**
310d99a87f8SAKASHI Takahiro * efi_get_next_variable_name() - enumerate the current variable names
311d99a87f8SAKASHI Takahiro * @variable_name_size: size of variable_name buffer in byte
312d99a87f8SAKASHI Takahiro * @variable_name: name of uefi variable's name in u16
313d99a87f8SAKASHI Takahiro * @vendor: vendor's guid
314d99a87f8SAKASHI Takahiro *
315d99a87f8SAKASHI Takahiro * This function implements the GetNextVariableName service.
31677d4d396SHeinrich Schuchardt *
31777d4d396SHeinrich Schuchardt * See the Unified Extensible Firmware Interface (UEFI) specification for
318d99a87f8SAKASHI Takahiro * details: http://wiki.phoenix.com/wiki/index.php/
319d99a87f8SAKASHI Takahiro * EFI_RUNTIME_SERVICES#GetNextVariableName.28.29
32077d4d396SHeinrich Schuchardt *
32177d4d396SHeinrich Schuchardt * Return: status code
32277d4d396SHeinrich Schuchardt */
efi_get_next_variable_name(efi_uintn_t * variable_name_size,u16 * variable_name,const efi_guid_t * vendor)32345c66f9cSHeinrich Schuchardt efi_status_t EFIAPI efi_get_next_variable_name(efi_uintn_t *variable_name_size,
32445c66f9cSHeinrich Schuchardt u16 *variable_name,
3250bda81bfSHeinrich Schuchardt const efi_guid_t *vendor)
326ad644e7cSRob Clark {
327d99a87f8SAKASHI Takahiro char *native_name, *variable;
328d99a87f8SAKASHI Takahiro ssize_t name_len, list_len;
329d99a87f8SAKASHI Takahiro char regex[256];
330d99a87f8SAKASHI Takahiro char * const regexlist[] = {regex};
331d99a87f8SAKASHI Takahiro u32 attributes;
332d99a87f8SAKASHI Takahiro int i;
333d99a87f8SAKASHI Takahiro efi_status_t ret;
334d99a87f8SAKASHI Takahiro
335778e6af8SRob Clark EFI_ENTRY("%p \"%ls\" %pUl", variable_name_size, variable_name, vendor);
336ad644e7cSRob Clark
337d99a87f8SAKASHI Takahiro if (!variable_name_size || !variable_name || !vendor)
338*e7dae584SHeinrich Schuchardt return EFI_EXIT(EFI_INVALID_PARAMETER);
339d99a87f8SAKASHI Takahiro
340d99a87f8SAKASHI Takahiro if (variable_name[0]) {
341d99a87f8SAKASHI Takahiro /* check null-terminated string */
342d99a87f8SAKASHI Takahiro for (i = 0; i < *variable_name_size; i++)
343d99a87f8SAKASHI Takahiro if (!variable_name[i])
344d99a87f8SAKASHI Takahiro break;
345d99a87f8SAKASHI Takahiro if (i >= *variable_name_size)
346d99a87f8SAKASHI Takahiro return EFI_EXIT(EFI_INVALID_PARAMETER);
347d99a87f8SAKASHI Takahiro
348d99a87f8SAKASHI Takahiro /* search for the last-returned variable */
349d99a87f8SAKASHI Takahiro ret = efi_to_native(&native_name, variable_name, vendor);
350d99a87f8SAKASHI Takahiro if (ret)
351d99a87f8SAKASHI Takahiro return EFI_EXIT(ret);
352d99a87f8SAKASHI Takahiro
353d99a87f8SAKASHI Takahiro name_len = strlen(native_name);
354d99a87f8SAKASHI Takahiro for (variable = efi_variables_list; variable && *variable;) {
355d99a87f8SAKASHI Takahiro if (!strncmp(variable, native_name, name_len) &&
356d99a87f8SAKASHI Takahiro variable[name_len] == '=')
357d99a87f8SAKASHI Takahiro break;
358d99a87f8SAKASHI Takahiro
359d99a87f8SAKASHI Takahiro variable = strchr(variable, '\n');
360d99a87f8SAKASHI Takahiro if (variable)
361d99a87f8SAKASHI Takahiro variable++;
362d99a87f8SAKASHI Takahiro }
363d99a87f8SAKASHI Takahiro
364d99a87f8SAKASHI Takahiro free(native_name);
365d99a87f8SAKASHI Takahiro if (!(variable && *variable))
366d99a87f8SAKASHI Takahiro return EFI_EXIT(EFI_INVALID_PARAMETER);
367d99a87f8SAKASHI Takahiro
368d99a87f8SAKASHI Takahiro /* next variable */
369d99a87f8SAKASHI Takahiro variable = strchr(variable, '\n');
370d99a87f8SAKASHI Takahiro if (variable)
371d99a87f8SAKASHI Takahiro variable++;
372d99a87f8SAKASHI Takahiro if (!(variable && *variable))
373d99a87f8SAKASHI Takahiro return EFI_EXIT(EFI_NOT_FOUND);
374d99a87f8SAKASHI Takahiro } else {
375d99a87f8SAKASHI Takahiro /*
376d99a87f8SAKASHI Takahiro *new search: free a list used in the previous search
377d99a87f8SAKASHI Takahiro */
378d99a87f8SAKASHI Takahiro free(efi_variables_list);
379d99a87f8SAKASHI Takahiro efi_variables_list = NULL;
380d99a87f8SAKASHI Takahiro efi_cur_variable = NULL;
381d99a87f8SAKASHI Takahiro
382d99a87f8SAKASHI Takahiro snprintf(regex, 256, "efi_.*-.*-.*-.*-.*_.*");
383d99a87f8SAKASHI Takahiro list_len = hexport_r(&env_htab, '\n',
384d99a87f8SAKASHI Takahiro H_MATCH_REGEX | H_MATCH_KEY,
385d99a87f8SAKASHI Takahiro &efi_variables_list, 0, 1, regexlist);
386eefb790eSHeinrich Schuchardt /* 1 indicates that no match was found */
387eefb790eSHeinrich Schuchardt if (list_len <= 1)
388d99a87f8SAKASHI Takahiro return EFI_EXIT(EFI_NOT_FOUND);
389d99a87f8SAKASHI Takahiro
390d99a87f8SAKASHI Takahiro variable = efi_variables_list;
391d99a87f8SAKASHI Takahiro }
392d99a87f8SAKASHI Takahiro
393d99a87f8SAKASHI Takahiro ret = parse_uboot_variable(variable, variable_name_size, variable_name,
394d99a87f8SAKASHI Takahiro vendor, &attributes);
395d99a87f8SAKASHI Takahiro
396d99a87f8SAKASHI Takahiro return EFI_EXIT(ret);
397ad644e7cSRob Clark }
398ad644e7cSRob Clark
39977d4d396SHeinrich Schuchardt /**
40077d4d396SHeinrich Schuchardt * efi_efi_set_variable() - set value of a UEFI variable
40177d4d396SHeinrich Schuchardt *
40277d4d396SHeinrich Schuchardt * This function implements the SetVariable runtime service.
40377d4d396SHeinrich Schuchardt *
40477d4d396SHeinrich Schuchardt * See the Unified Extensible Firmware Interface (UEFI) specification for
40577d4d396SHeinrich Schuchardt * details.
40677d4d396SHeinrich Schuchardt *
40777d4d396SHeinrich Schuchardt * @variable_name: name of the variable
40877d4d396SHeinrich Schuchardt * @vendor: vendor GUID
40977d4d396SHeinrich Schuchardt * @attributes: attributes of the variable
41077d4d396SHeinrich Schuchardt * @data_size: size of the buffer with the variable value
41177d4d396SHeinrich Schuchardt * @data: buffer with the variable value
41277d4d396SHeinrich Schuchardt * Return: status code
41377d4d396SHeinrich Schuchardt */
efi_set_variable(u16 * variable_name,const efi_guid_t * vendor,u32 attributes,efi_uintn_t data_size,const void * data)4140bda81bfSHeinrich Schuchardt efi_status_t EFIAPI efi_set_variable(u16 *variable_name,
4150bda81bfSHeinrich Schuchardt const efi_guid_t *vendor, u32 attributes,
416452257a3SHeinrich Schuchardt efi_uintn_t data_size, const void *data)
417ad644e7cSRob Clark {
418dcdb64f7SHeinrich Schuchardt char *native_name = NULL, *val = NULL, *s;
419ad644e7cSRob Clark efi_status_t ret = EFI_SUCCESS;
420ad644e7cSRob Clark u32 attr;
421ad644e7cSRob Clark
42245c66f9cSHeinrich Schuchardt EFI_ENTRY("\"%ls\" %pUl %x %zu %p", variable_name, vendor, attributes,
423ad644e7cSRob Clark data_size, data);
424ad644e7cSRob Clark
425dcdb64f7SHeinrich Schuchardt if (!variable_name || !vendor) {
426dcdb64f7SHeinrich Schuchardt ret = EFI_INVALID_PARAMETER;
427dcdb64f7SHeinrich Schuchardt goto out;
428dcdb64f7SHeinrich Schuchardt }
429ad644e7cSRob Clark
430dcdb64f7SHeinrich Schuchardt ret = efi_to_native(&native_name, variable_name, vendor);
431ad644e7cSRob Clark if (ret)
432dcdb64f7SHeinrich Schuchardt goto out;
433ad644e7cSRob Clark
434ad644e7cSRob Clark #define ACCESS_ATTR (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)
435ad644e7cSRob Clark
436ad644e7cSRob Clark if ((data_size == 0) || !(attributes & ACCESS_ATTR)) {
437ad644e7cSRob Clark /* delete the variable: */
438ad644e7cSRob Clark env_set(native_name, NULL);
439dcdb64f7SHeinrich Schuchardt ret = EFI_SUCCESS;
440dcdb64f7SHeinrich Schuchardt goto out;
441ad644e7cSRob Clark }
442ad644e7cSRob Clark
443ad644e7cSRob Clark val = env_get(native_name);
444ad644e7cSRob Clark if (val) {
445ad644e7cSRob Clark parse_attr(val, &attr);
446ad644e7cSRob Clark
447dcdb64f7SHeinrich Schuchardt if (attr & READ_ONLY) {
448dcdb64f7SHeinrich Schuchardt /* We should not free val */
449dcdb64f7SHeinrich Schuchardt val = NULL;
450dcdb64f7SHeinrich Schuchardt ret = EFI_WRITE_PROTECTED;
451dcdb64f7SHeinrich Schuchardt goto out;
452dcdb64f7SHeinrich Schuchardt }
453ad644e7cSRob Clark }
454ad644e7cSRob Clark
455ad644e7cSRob Clark val = malloc(2 * data_size + strlen("{ro,run,boot}(blob)") + 1);
456dadc2bddSHeinrich Schuchardt if (!val) {
457dadc2bddSHeinrich Schuchardt ret = EFI_OUT_OF_RESOURCES;
458dadc2bddSHeinrich Schuchardt goto out;
459dadc2bddSHeinrich Schuchardt }
460ad644e7cSRob Clark
461ad644e7cSRob Clark s = val;
462ad644e7cSRob Clark
46377d4d396SHeinrich Schuchardt /*
46477d4d396SHeinrich Schuchardt * store attributes
46577d4d396SHeinrich Schuchardt * TODO: several attributes are not supported
46677d4d396SHeinrich Schuchardt */
467ad644e7cSRob Clark attributes &= (EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS);
468ad644e7cSRob Clark s += sprintf(s, "{");
469ad644e7cSRob Clark while (attributes) {
470ad644e7cSRob Clark u32 attr = 1 << (ffs(attributes) - 1);
471ad644e7cSRob Clark
472ad644e7cSRob Clark if (attr == EFI_VARIABLE_BOOTSERVICE_ACCESS)
473ad644e7cSRob Clark s += sprintf(s, "boot");
474ad644e7cSRob Clark else if (attr == EFI_VARIABLE_RUNTIME_ACCESS)
475ad644e7cSRob Clark s += sprintf(s, "run");
476ad644e7cSRob Clark
477ad644e7cSRob Clark attributes &= ~attr;
478ad644e7cSRob Clark if (attributes)
479ad644e7cSRob Clark s += sprintf(s, ",");
480ad644e7cSRob Clark }
481ad644e7cSRob Clark s += sprintf(s, "}");
482ad644e7cSRob Clark
483ad644e7cSRob Clark /* store payload: */
484ad644e7cSRob Clark s += sprintf(s, "(blob)");
4858377ee36SHeinrich Schuchardt s = bin2hex(s, data, data_size);
486ad644e7cSRob Clark *s = '\0';
487ad644e7cSRob Clark
488ad644e7cSRob Clark debug("%s: setting: %s=%s\n", __func__, native_name, val);
489ad644e7cSRob Clark
490ad644e7cSRob Clark if (env_set(native_name, val))
491ad644e7cSRob Clark ret = EFI_DEVICE_ERROR;
492ad644e7cSRob Clark
493dcdb64f7SHeinrich Schuchardt out:
494dcdb64f7SHeinrich Schuchardt free(native_name);
495ad644e7cSRob Clark free(val);
496ad644e7cSRob Clark
497ad644e7cSRob Clark return EFI_EXIT(ret);
498ad644e7cSRob Clark }
499