1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Helper functions used by the EFI stub on multiple
4  * architectures. This should be #included by the EFI stub
5  * implementation files.
6  *
7  * Copyright 2011 Intel Corporation; author Matt Fleming
8  */
9 
10 #include <linux/efi.h>
11 #include <asm/efi.h>
12 
13 #include "efistub.h"
14 
15 /*
16  * Some firmware implementations have problems reading files in one go.
17  * A read chunk size of 1MB seems to work for most platforms.
18  *
19  * Unfortunately, reading files in chunks triggers *other* bugs on some
20  * platforms, so we provide a way to disable this workaround, which can
21  * be done by passing "efi=nochunk" on the EFI boot stub command line.
22  *
23  * If you experience issues with initrd images being corrupt it's worth
24  * trying efi=nochunk, but chunking is enabled by default on x86 because
25  * there are far more machines that require the workaround than those that
26  * break with it enabled.
27  */
28 #define EFI_READ_CHUNK_SIZE	SZ_1M
29 
30 struct file_info {
31 	efi_file_protocol_t *handle;
32 	u64 size;
33 };
34 
35 static efi_status_t efi_file_size(void *__fh, efi_char16_t *filename_16,
36 				  void **handle, u64 *file_sz)
37 {
38 	efi_file_protocol_t *h, *fh = __fh;
39 	efi_file_info_t *info;
40 	efi_status_t status;
41 	efi_guid_t info_guid = EFI_FILE_INFO_ID;
42 	unsigned long info_sz;
43 
44 	status = fh->open(fh, &h, filename_16, EFI_FILE_MODE_READ, 0);
45 	if (status != EFI_SUCCESS) {
46 		efi_printk("Failed to open file: ");
47 		efi_char16_printk(filename_16);
48 		efi_printk("\n");
49 		return status;
50 	}
51 
52 	*handle = h;
53 
54 	info_sz = 0;
55 	status = h->get_info(h, &info_guid, &info_sz, NULL);
56 	if (status != EFI_BUFFER_TOO_SMALL) {
57 		efi_printk("Failed to get file info size\n");
58 		return status;
59 	}
60 
61 grow:
62 	status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, info_sz,
63 			     (void **)&info);
64 	if (status != EFI_SUCCESS) {
65 		efi_printk("Failed to alloc mem for file info\n");
66 		return status;
67 	}
68 
69 	status = h->get_info(h, &info_guid, &info_sz, info);
70 	if (status == EFI_BUFFER_TOO_SMALL) {
71 		efi_bs_call(free_pool, info);
72 		goto grow;
73 	}
74 
75 	*file_sz = info->file_size;
76 	efi_bs_call(free_pool, info);
77 
78 	if (status != EFI_SUCCESS)
79 		efi_printk("Failed to get initrd info\n");
80 
81 	return status;
82 }
83 
84 static efi_status_t efi_file_read(efi_file_protocol_t *handle,
85 				  unsigned long *size, void *addr)
86 {
87 	return handle->read(handle, size, addr);
88 }
89 
90 static efi_status_t efi_file_close(efi_file_protocol_t *handle)
91 {
92 	return handle->close(handle);
93 }
94 
95 static efi_status_t efi_open_volume(efi_loaded_image_t *image,
96 				    efi_file_protocol_t **__fh)
97 {
98 	efi_simple_file_system_protocol_t *io;
99 	efi_file_protocol_t *fh;
100 	efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID;
101 	efi_status_t status;
102 	efi_handle_t handle = image->device_handle;
103 
104 	status = efi_bs_call(handle_protocol, handle, &fs_proto, (void **)&io);
105 	if (status != EFI_SUCCESS) {
106 		efi_printk("Failed to handle fs_proto\n");
107 		return status;
108 	}
109 
110 	status = io->open_volume(io, &fh);
111 	if (status != EFI_SUCCESS)
112 		efi_printk("Failed to open volume\n");
113 	else
114 		*__fh = fh;
115 
116 	return status;
117 }
118 
119 /*
120  * Check the cmdline for a LILO-style file= arguments.
121  *
122  * We only support loading a file from the same filesystem as
123  * the kernel image.
124  */
125 efi_status_t handle_cmdline_files(efi_loaded_image_t *image,
126 				  char *cmd_line, char *option_string,
127 				  unsigned long max_addr,
128 				  unsigned long *load_addr,
129 				  unsigned long *load_size)
130 {
131 	unsigned long efi_chunk_size = ULONG_MAX;
132 	struct file_info *files;
133 	unsigned long file_addr;
134 	u64 file_size_total;
135 	efi_file_protocol_t *fh = NULL;
136 	efi_status_t status;
137 	int nr_files;
138 	char *str;
139 	int i, j, k;
140 
141 	if (IS_ENABLED(CONFIG_X86) && !nochunk())
142 		efi_chunk_size = EFI_READ_CHUNK_SIZE;
143 
144 	file_addr = 0;
145 	file_size_total = 0;
146 
147 	str = cmd_line;
148 
149 	j = 0;			/* See close_handles */
150 
151 	if (!load_addr || !load_size)
152 		return EFI_INVALID_PARAMETER;
153 
154 	*load_addr = 0;
155 	*load_size = 0;
156 
157 	if (!str || !*str)
158 		return EFI_SUCCESS;
159 
160 	for (nr_files = 0; *str; nr_files++) {
161 		str = strstr(str, option_string);
162 		if (!str)
163 			break;
164 
165 		str += strlen(option_string);
166 
167 		/* Skip any leading slashes */
168 		while (*str == '/' || *str == '\\')
169 			str++;
170 
171 		while (*str && *str != ' ' && *str != '\n')
172 			str++;
173 	}
174 
175 	if (!nr_files)
176 		return EFI_SUCCESS;
177 
178 	status = efi_bs_call(allocate_pool, EFI_LOADER_DATA,
179 			     nr_files * sizeof(*files), (void **)&files);
180 	if (status != EFI_SUCCESS) {
181 		pr_efi_err("Failed to alloc mem for file handle list\n");
182 		goto fail;
183 	}
184 
185 	str = cmd_line;
186 	for (i = 0; i < nr_files; i++) {
187 		struct file_info *file;
188 		efi_char16_t filename_16[256];
189 		efi_char16_t *p;
190 
191 		str = strstr(str, option_string);
192 		if (!str)
193 			break;
194 
195 		str += strlen(option_string);
196 
197 		file = &files[i];
198 		p = filename_16;
199 
200 		/* Skip any leading slashes */
201 		while (*str == '/' || *str == '\\')
202 			str++;
203 
204 		while (*str && *str != ' ' && *str != '\n') {
205 			if ((u8 *)p >= (u8 *)filename_16 + sizeof(filename_16))
206 				break;
207 
208 			if (*str == '/') {
209 				*p++ = '\\';
210 				str++;
211 			} else {
212 				*p++ = *str++;
213 			}
214 		}
215 
216 		*p = '\0';
217 
218 		/* Only open the volume once. */
219 		if (!i) {
220 			status = efi_open_volume(image, &fh);
221 			if (status != EFI_SUCCESS)
222 				goto free_files;
223 		}
224 
225 		status = efi_file_size(fh, filename_16, (void **)&file->handle,
226 				       &file->size);
227 		if (status != EFI_SUCCESS)
228 			goto close_handles;
229 
230 		file_size_total += file->size;
231 	}
232 
233 	if (file_size_total) {
234 		unsigned long addr;
235 
236 		/*
237 		 * Multiple files need to be at consecutive addresses in memory,
238 		 * so allocate enough memory for all the files.  This is used
239 		 * for loading multiple files.
240 		 */
241 		status = efi_allocate_pages(file_size_total, &file_addr, max_addr);
242 		if (status != EFI_SUCCESS) {
243 			pr_efi_err("Failed to alloc highmem for files\n");
244 			goto close_handles;
245 		}
246 
247 		/* We've run out of free low memory. */
248 		if (file_addr > max_addr) {
249 			pr_efi_err("We've run out of free low memory\n");
250 			status = EFI_INVALID_PARAMETER;
251 			goto free_file_total;
252 		}
253 
254 		addr = file_addr;
255 		for (j = 0; j < nr_files; j++) {
256 			unsigned long size;
257 
258 			size = files[j].size;
259 			while (size) {
260 				unsigned long chunksize;
261 
262 				if (size > efi_chunk_size)
263 					chunksize = efi_chunk_size;
264 				else
265 					chunksize = size;
266 
267 				status = efi_file_read(files[j].handle,
268 						       &chunksize,
269 						       (void *)addr);
270 				if (status != EFI_SUCCESS) {
271 					pr_efi_err("Failed to read file\n");
272 					goto free_file_total;
273 				}
274 				addr += chunksize;
275 				size -= chunksize;
276 			}
277 
278 			efi_file_close(files[j].handle);
279 		}
280 
281 	}
282 
283 	efi_bs_call(free_pool, files);
284 
285 	*load_addr = file_addr;
286 	*load_size = file_size_total;
287 
288 	return status;
289 
290 free_file_total:
291 	efi_free(file_size_total, file_addr);
292 
293 close_handles:
294 	for (k = j; k < i; k++)
295 		efi_file_close(files[k].handle);
296 free_files:
297 	efi_bs_call(free_pool, files);
298 fail:
299 	*load_addr = 0;
300 	*load_size = 0;
301 
302 	return status;
303 }
304