xref: /openbmc/u-boot/lib/efi_loader/efi_variable.c (revision 66c433ed4342e5761ee9b048c85fe47d31130b2e)
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