1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  *  EFI boot manager
4  *
5  *  Copyright (c) 2018 AKASHI Takahiro, et.al.
6  */
7 
8 #define LOG_CATEGORY LOGC_EFI
9 
10 #include <common.h>
11 #include <charset.h>
12 #include <log.h>
13 #include <malloc.h>
14 #include <efi_loader.h>
15 #include <asm/unaligned.h>
16 
17 /**
18  * efi_set_load_options() - set the load options of a loaded image
19  *
20  * @handle:		the image handle
21  * @load_options_size:	size of load options
22  * @load_options:	pointer to load options
23  * Return:		status code
24  */
efi_set_load_options(efi_handle_t handle,efi_uintn_t load_options_size,void * load_options)25 efi_status_t efi_set_load_options(efi_handle_t handle,
26 				  efi_uintn_t load_options_size,
27 				  void *load_options)
28 {
29 	struct efi_loaded_image *loaded_image_info;
30 	efi_status_t ret;
31 
32 	ret = EFI_CALL(systab.boottime->open_protocol(
33 					handle,
34 					&efi_guid_loaded_image,
35 					(void **)&loaded_image_info,
36 					efi_root, NULL,
37 					EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL));
38 	if (ret != EFI_SUCCESS)
39 		return EFI_INVALID_PARAMETER;
40 
41 	loaded_image_info->load_options = load_options;
42 	loaded_image_info->load_options_size = load_options_size;
43 
44 	return EFI_CALL(systab.boottime->close_protocol(handle,
45 							&efi_guid_loaded_image,
46 							efi_root, NULL));
47 }
48 
49 /**
50  * efi_deserialize_load_option() - parse serialized data
51  *
52  * Parse serialized data describing a load option and transform it to the
53  * efi_load_option structure.
54  *
55  * @lo:		pointer to target
56  * @data:	serialized data
57  * @size:	size of the load option, on return size of the optional data
58  * Return:	status code
59  */
efi_deserialize_load_option(struct efi_load_option * lo,u8 * data,efi_uintn_t * size)60 efi_status_t efi_deserialize_load_option(struct efi_load_option *lo, u8 *data,
61 					 efi_uintn_t *size)
62 {
63 	efi_uintn_t len;
64 
65 	len = sizeof(u32);
66 	if (*size < len + 2 * sizeof(u16))
67 		return EFI_INVALID_PARAMETER;
68 	lo->attributes = get_unaligned_le32(data);
69 	data += len;
70 	*size -= len;
71 
72 	len = sizeof(u16);
73 	lo->file_path_length = get_unaligned_le16(data);
74 	data += len;
75 	*size -= len;
76 
77 	lo->label = (u16 *)data;
78 	len = u16_strnlen(lo->label, *size / sizeof(u16) - 1);
79 	if (lo->label[len])
80 		return EFI_INVALID_PARAMETER;
81 	len = (len + 1) * sizeof(u16);
82 	if (*size < len)
83 		return EFI_INVALID_PARAMETER;
84 	data += len;
85 	*size -= len;
86 
87 	len = lo->file_path_length;
88 	if (*size < len)
89 		return EFI_INVALID_PARAMETER;
90 	lo->file_path = (struct efi_device_path *)data;
91 	if (efi_dp_check_length(lo->file_path, len) < 0)
92 		return EFI_INVALID_PARAMETER;
93 	data += len;
94 	*size -= len;
95 
96 	lo->optional_data = data;
97 
98 	return EFI_SUCCESS;
99 }
100 
101 /**
102  * efi_serialize_load_option() - serialize load option
103  *
104  * Serialize efi_load_option structure into byte stream for BootXXXX.
105  *
106  * @data:	buffer for serialized data
107  * @lo:		load option
108  * Return:	size of allocated buffer
109  */
efi_serialize_load_option(struct efi_load_option * lo,u8 ** data)110 unsigned long efi_serialize_load_option(struct efi_load_option *lo, u8 **data)
111 {
112 	unsigned long label_len;
113 	unsigned long size;
114 	u8 *p;
115 
116 	label_len = (u16_strlen(lo->label) + 1) * sizeof(u16);
117 
118 	/* total size */
119 	size = sizeof(lo->attributes);
120 	size += sizeof(lo->file_path_length);
121 	size += label_len;
122 	size += lo->file_path_length;
123 	if (lo->optional_data)
124 		size += (utf8_utf16_strlen((const char *)lo->optional_data)
125 					   + 1) * sizeof(u16);
126 	p = malloc(size);
127 	if (!p)
128 		return 0;
129 
130 	/* copy data */
131 	*data = p;
132 	memcpy(p, &lo->attributes, sizeof(lo->attributes));
133 	p += sizeof(lo->attributes);
134 
135 	memcpy(p, &lo->file_path_length, sizeof(lo->file_path_length));
136 	p += sizeof(lo->file_path_length);
137 
138 	memcpy(p, lo->label, label_len);
139 	p += label_len;
140 
141 	memcpy(p, lo->file_path, lo->file_path_length);
142 	p += lo->file_path_length;
143 
144 	if (lo->optional_data) {
145 		utf8_utf16_strcpy((u16 **)&p, (const char *)lo->optional_data);
146 		p += sizeof(u16); /* size of trailing \0 */
147 	}
148 	return size;
149 }
150