xref: /kvm-unit-tests/lib/efi.c (revision 9f34c8103688351cb99ae7a277ad08f9ef6d278d)
1 /*
2  * EFI-related functions to set up and run test cases in EFI
3  *
4  * Copyright (c) 2021, SUSE, Varad Gautam <varad.gautam@suse.com>
5  * Copyright (c) 2021, Google Inc, Zixuan Wang <zixuanwang@google.com>
6  *
7  * SPDX-License-Identifier: LGPL-2.0-or-later
8  */
9 #include <libcflat.h>
10 #include <argv.h>
11 #include <ctype.h>
12 #include <stdlib.h>
13 #include <asm/setup.h>
14 #include "efi.h"
15 #include "libfdt/libfdt.h"
16 
17 /* From each arch */
18 extern char *initrd;
19 extern u32 initrd_size;
20 
21 /* From lib/argv.c */
22 extern int __argc, __envc;
23 extern char *__argv[100];
24 extern char *__environ[200];
25 
26 extern char _text;
27 
28 extern int main(int argc, char **argv, char **envp);
29 
30 efi_system_table_t *efi_system_table = NULL;
31 
32 #ifdef __riscv
33 #define RISCV_EFI_BOOT_PROTOCOL_GUID EFI_GUID(0xccd15fec, 0x6f73, 0x4eec,  0x83, 0x95, 0x3e, 0x69, 0xe4, 0xb9, 0x40, 0xbf)
34 
35 unsigned long boot_hartid;
36 
37 struct riscv_efi_boot_protocol {
38 	u64 revision;
39 	efi_status_t (*get_boot_hartid)(struct riscv_efi_boot_protocol *,
40 		      unsigned long *boot_hartid);
41 };
42 
43 static efi_status_t efi_get_boot_hartid(void)
44 {
45 	efi_guid_t boot_protocol_guid = RISCV_EFI_BOOT_PROTOCOL_GUID;
46 	struct riscv_efi_boot_protocol *boot_protocol;
47 	efi_status_t status;
48 
49 	status = efi_bs_call(locate_protocol, &boot_protocol_guid, NULL,
50 			     (void **)&boot_protocol);
51 	if (status != EFI_SUCCESS)
52 		return status;
53 	return efi_call_proto(boot_protocol, get_boot_hartid, &boot_hartid);
54 }
55 #endif
56 
57 static void efi_free_pool(void *ptr)
58 {
59 	efi_bs_call(free_pool, ptr);
60 }
61 
62 efi_status_t efi_get_memory_map(struct efi_boot_memmap *map)
63 {
64 	efi_memory_desc_t *m = NULL;
65 	efi_status_t status;
66 	unsigned long key = 0, map_size = 0, desc_size = 0;
67 	u32 desc_ver;
68 
69 	status = efi_bs_call(get_memory_map, &map_size,
70 			     NULL, &key, &desc_size, &desc_ver);
71 	if (status != EFI_BUFFER_TOO_SMALL || map_size == 0)
72 		goto out;
73 
74 	/*
75 	 * Pad map_size with additional descriptors so we don't need to
76 	 * retry.
77 	 */
78 	map_size += 4 * desc_size;
79 	*map->buff_size = map_size;
80 	status = efi_bs_call(allocate_pool, EFI_LOADER_DATA,
81 			     map_size, (void **)&m);
82 	if (status != EFI_SUCCESS)
83 		goto out;
84 
85 	/* Get the map. */
86 	status = efi_bs_call(get_memory_map, &map_size,
87 			     m, &key, &desc_size, &desc_ver);
88 	if (status != EFI_SUCCESS) {
89 		efi_free_pool(m);
90 		goto out;
91 	}
92 
93 	*map->desc_ver = desc_ver;
94 	*map->desc_size = desc_size;
95 	*map->map_size = map_size;
96 	*map->key_ptr = key;
97 out:
98 	*map->map = m;
99 	return status;
100 }
101 
102 efi_status_t efi_exit_boot_services(void *handle, struct efi_boot_memmap *map)
103 {
104 	return efi_bs_call(exit_boot_services, handle, *map->key_ptr);
105 }
106 
107 efi_status_t efi_get_system_config_table(efi_guid_t table_guid, void **table)
108 {
109 	size_t i;
110 	efi_config_table_t *tables;
111 
112 	tables = (efi_config_table_t *)efi_system_table->tables;
113 	for (i = 0; i < efi_system_table->nr_tables; i++) {
114 		if (!memcmp(&table_guid, &tables[i].guid, sizeof(efi_guid_t))) {
115 			*table = tables[i].table;
116 			return EFI_SUCCESS;
117 		}
118 	}
119 	return EFI_NOT_FOUND;
120 }
121 
122 static void efi_exit(efi_status_t code)
123 {
124 	exit(code);
125 
126 	/*
127 	 * Fallback to UEFI reset_system() service, in case testdev is
128 	 * missing and exit() does not properly exit.
129 	 */
130 	efi_rs_call(reset_system, EFI_RESET_SHUTDOWN, code, 0, NULL);
131 }
132 
133 /* Adapted from drivers/firmware/efi/libstub/efi-stub.c */
134 static char *efi_convert_cmdline(struct efi_loaded_image_64 *image, int *cmd_line_len)
135 {
136 	const u16 *s2;
137 	unsigned long cmdline_addr = 0;
138 	int options_chars = image->load_options_size;
139 	const u16 *options = image->load_options;
140 	int options_bytes = 0, safe_options_bytes = 0;  /* UTF-8 bytes */
141 	bool in_quote = false;
142 	efi_status_t status;
143 	const int COMMAND_LINE_SIZE = 2048;
144 
145 	if (options) {
146 		s2 = options;
147 		while (options_bytes < COMMAND_LINE_SIZE && options_chars--) {
148 			u16 c = *s2++;
149 
150 			if (c < 0x80) {
151 				if (c == L'\0' || c == L'\n')
152 					break;
153 				if (c == L'"')
154 					in_quote = !in_quote;
155 				else if (!in_quote && isspace((char)c))
156 					safe_options_bytes = options_bytes;
157 
158 				options_bytes++;
159 				continue;
160 			}
161 
162 			/*
163 			 * Get the number of UTF-8 bytes corresponding to a
164 			 * UTF-16 character.
165 			 * The first part handles everything in the BMP.
166 			 */
167 			options_bytes += 2 + (c >= 0x800);
168 			/*
169 			 * Add one more byte for valid surrogate pairs. Invalid
170 			 * surrogates will be replaced with 0xfffd and take up
171 			 * only 3 bytes.
172 			 */
173 			if ((c & 0xfc00) == 0xd800) {
174 				/*
175 				 * If the very last word is a high surrogate,
176 				 * we must ignore it since we can't access the
177 				 * low surrogate.
178 				 */
179 				if (!options_chars) {
180 					options_bytes -= 3;
181 				} else if ((*s2 & 0xfc00) == 0xdc00) {
182 					options_bytes++;
183 					options_chars--;
184 					s2++;
185 				}
186 			}
187 		}
188 		if (options_bytes >= COMMAND_LINE_SIZE) {
189 			options_bytes = safe_options_bytes;
190 			printf("Command line is too long: truncated to %d bytes\n",
191 			       options_bytes);
192 		}
193 	}
194 
195 	options_bytes++;        /* NUL termination */
196 
197 	status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, options_bytes, (void **)&cmdline_addr);
198 	if (status != EFI_SUCCESS)
199 		return NULL;
200 
201 	snprintf((char *)cmdline_addr, options_bytes, "%.*ls", options_bytes - 1, options);
202 
203 	*cmd_line_len = options_bytes;
204 	return (char *)cmdline_addr;
205 }
206 
207 /*
208  * Open the file and read it into a buffer.
209  */
210 static void efi_load_image(efi_handle_t handle, struct efi_loaded_image_64 *image, void **data,
211 			   int *datasize, efi_char16_t *path_name)
212 {
213 	uint64_t buffer_size = sizeof(efi_file_info_t);
214 	efi_file_info_t *file_info;
215 	efi_file_io_interface_t *io_if;
216 	efi_file_t *root, *file;
217 	efi_status_t status;
218 	efi_guid_t file_system_proto_guid = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID;
219 	efi_guid_t file_info_guid = EFI_FILE_INFO_ID;
220 
221 	/* Open the device */
222 	status = efi_bs_call(handle_protocol, image->device_handle, &file_system_proto_guid,
223 			     (void **)&io_if);
224 	if (status != EFI_SUCCESS)
225 		return;
226 
227 	status = io_if->open_volume(io_if, &root);
228 	if (status != EFI_SUCCESS)
229 		return;
230 
231 	/* And then open the file */
232 	status = root->open(root, &file, path_name, EFI_FILE_MODE_READ, 0);
233 	if (status != EFI_SUCCESS) {
234 		printf("Failed to open %ls - %lx\n", path_name, status);
235 		assert(status == EFI_SUCCESS);
236 	}
237 
238 	/* Find the file size in order to allocate the buffer */
239 	status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, buffer_size, (void **)&file_info);
240 	if (status != EFI_SUCCESS)
241 		return;
242 
243 	status = file->get_info(file, &file_info_guid, &buffer_size, file_info);
244 	if (status == EFI_BUFFER_TOO_SMALL) {
245 		efi_free_pool(file_info);
246 		status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, buffer_size, (void **)&file_info);
247 		assert(file_info);
248 		status = file->get_info(file, &file_info_guid, &buffer_size, file_info);
249 	}
250 	assert(status == EFI_SUCCESS);
251 
252 	buffer_size = file_info->file_size;
253 
254 	efi_free_pool(file_info);
255 
256 	status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, buffer_size, (void **)data);
257 	assert(*data);
258 	/* Perform the actual read */
259 	status = file->read(file, &buffer_size, *data);
260 	if (status == EFI_BUFFER_TOO_SMALL) {
261 		efi_free_pool(*data);
262 		status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, buffer_size, (void **)data);
263 		status = file->read(file, &buffer_size, *data);
264 	}
265 	assert(status == EFI_SUCCESS);
266 
267 	*datasize = buffer_size;
268 }
269 
270 static int efi_grow_buffer(efi_status_t *status, void **buffer, uint64_t buffer_size)
271 {
272 	int try_again;
273 
274 	if (!*buffer && buffer_size) {
275 		*status = EFI_BUFFER_TOO_SMALL;
276 	}
277 
278 	try_again = 0;
279 	if (*status == EFI_BUFFER_TOO_SMALL) {
280 		if (*buffer)
281 			efi_free_pool(*buffer);
282 
283 		efi_bs_call(allocate_pool, EFI_LOADER_DATA, buffer_size, buffer);
284 		if (*buffer) {
285 			try_again = 1;
286 		} else {
287 			*status = EFI_OUT_OF_RESOURCES;
288 		}
289 	}
290 
291 	if (!try_again && EFI_ERROR(*status) && *buffer) {
292 		efi_free_pool(*buffer);
293 		*buffer = NULL;
294 	}
295 
296 	return try_again;
297 }
298 
299 static void* efi_get_var(efi_handle_t handle, struct efi_loaded_image_64 *image, efi_char16_t *var)
300 {
301 	efi_status_t status = EFI_SUCCESS;
302 	void *val = NULL;
303 	uint64_t val_size = 100;
304 	efi_guid_t efi_var_guid = EFI_VAR_GUID;
305 
306 	while (efi_grow_buffer(&status, &val, val_size + sizeof(efi_char16_t)))
307 		status = efi_rs_call(get_variable, var, &efi_var_guid, NULL, &val_size, val);
308 
309 	if (val)
310 		((efi_char16_t *)val)[val_size / sizeof(efi_char16_t)] = L'\0';
311 
312 	return val;
313 }
314 
315 static void *efi_get_fdt(efi_handle_t handle, struct efi_loaded_image_64 *image)
316 {
317 	efi_char16_t var[] = ENV_VARNAME_DTBFILE;
318 	efi_char16_t *val;
319 	void *fdt = NULL;
320 	int fdtsize = 0;
321 
322 	val = efi_get_var(handle, image, var);
323 	if (val) {
324 		efi_load_image(handle, image, &fdt, &fdtsize, val);
325 		if (fdtsize == 0)
326 			return NULL;
327 	} else if (efi_get_system_config_table(DEVICE_TREE_GUID, &fdt) != EFI_SUCCESS) {
328 		return NULL;
329 	}
330 
331 	return fdt_check_header(fdt) == 0 ? fdt : NULL;
332 }
333 
334 static const struct {
335 	struct efi_vendor_dev_path	vendor;
336 	struct efi_generic_dev_path	end;
337 } __packed initrd_dev_path = {
338 	{
339 		{
340 			EFI_DEV_MEDIA,
341 			EFI_DEV_MEDIA_VENDOR,
342 			sizeof(struct efi_vendor_dev_path),
343 		},
344 		LINUX_EFI_INITRD_MEDIA_GUID
345 	}, {
346 		EFI_DEV_END_PATH,
347 		EFI_DEV_END_ENTIRE,
348 		sizeof(struct efi_generic_dev_path)
349 	}
350 };
351 
352 static void efi_load_initrd(void)
353 {
354 	efi_guid_t lf2_proto_guid = EFI_LOAD_FILE2_PROTOCOL_GUID;
355 	efi_device_path_protocol_t *dp;
356 	efi_load_file2_protocol_t *lf2;
357 	efi_handle_t handle;
358 	efi_status_t status;
359 	unsigned long file_size = 0;
360 
361 	initrd = NULL;
362 	initrd_size = 0;
363 
364 	dp = (efi_device_path_protocol_t *)&initrd_dev_path;
365 	status = efi_bs_call(locate_device_path, &lf2_proto_guid, &dp, &handle);
366 	if (status != EFI_SUCCESS)
367 		return;
368 
369 	status = efi_bs_call(handle_protocol, handle, &lf2_proto_guid, (void **)&lf2);
370 	assert(status == EFI_SUCCESS);
371 
372 	status = efi_call_proto(lf2, load_file, dp, false, &file_size, NULL);
373 	assert(status == EFI_BUFFER_TOO_SMALL);
374 
375 	status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, file_size, (void **)&initrd);
376 	assert(status == EFI_SUCCESS);
377 
378 	status = efi_call_proto(lf2, load_file, dp, false, &file_size, (void *)initrd);
379 	assert(status == EFI_SUCCESS);
380 
381 	initrd_size = (u32)file_size;
382 
383 	/*
384 	 * UEFI appends initrd=initrd to the command line when an initrd is present.
385 	 * Remove it in order to avoid confusing unit tests.
386 	 */
387 	if (!strcmp(__argv[__argc - 1], "initrd=initrd")) {
388 		__argv[__argc - 1] = NULL;
389 		__argc -= 1;
390 	}
391 }
392 
393 efi_status_t efi_main(efi_handle_t handle, efi_system_table_t *sys_tab)
394 {
395 	int ret;
396 	efi_status_t status;
397 	efi_bootinfo_t efi_bootinfo;
398 
399 	efi_system_table = sys_tab;
400 
401 	/* Memory map struct values */
402 	efi_memory_desc_t *map = NULL;
403 	unsigned long map_size = 0, desc_size = 0, key = 0, buff_size = 0;
404 	u32 desc_ver;
405 
406 	/* Helper variables needed to get the cmdline */
407 	struct efi_loaded_image_64 *image;
408 	efi_guid_t loaded_image_proto = LOADED_IMAGE_PROTOCOL_GUID;
409 	char *cmdline_ptr = NULL;
410 	int cmdline_size = 0;
411 
412 	/*
413 	 * Get a handle to the loaded image protocol.  This is used to get
414 	 * information about the running image, such as size and the command
415 	 * line.
416 	 */
417 	status = efi_bs_call(handle_protocol, handle, &loaded_image_proto, (void *)&image);
418 	if (status != EFI_SUCCESS) {
419 		printf("Failed to get loaded image protocol\n");
420 		goto efi_main_error;
421 	}
422 
423 	cmdline_ptr = efi_convert_cmdline(image, &cmdline_size);
424 	if (!cmdline_ptr) {
425 		printf("getting command line via LOADED_IMAGE_PROTOCOL\n");
426 		status = EFI_OUT_OF_RESOURCES;
427 		goto efi_main_error;
428 	}
429 	setup_args(cmdline_ptr);
430 
431 	efi_load_initrd();
432 
433 	efi_bootinfo.fdt = efi_get_fdt(handle, image);
434 	/* Set up efi_bootinfo */
435 	efi_bootinfo.mem_map.map = &map;
436 	efi_bootinfo.mem_map.map_size = &map_size;
437 	efi_bootinfo.mem_map.desc_size = &desc_size;
438 	efi_bootinfo.mem_map.desc_ver = &desc_ver;
439 	efi_bootinfo.mem_map.key_ptr = &key;
440 	efi_bootinfo.mem_map.buff_size = &buff_size;
441 
442 	/* Get EFI memory map */
443 	status = efi_get_memory_map(&efi_bootinfo.mem_map);
444 	if (status != EFI_SUCCESS) {
445 		printf("Failed to get memory map\n");
446 		goto efi_main_error;
447 	}
448 
449 #ifdef __riscv
450 	status = efi_get_boot_hartid();
451 	if (status != EFI_SUCCESS) {
452 		printf("Failed to get boot haritd\n");
453 		goto efi_main_error;
454 	}
455 #endif
456 
457 	/*
458 	 * Exit EFI boot services, let kvm-unit-tests take full control of the
459 	 * guest
460 	 */
461 	status = efi_exit_boot_services(handle, &efi_bootinfo.mem_map);
462 	if (status != EFI_SUCCESS) {
463 		printf("Failed to exit boot services\n");
464 		goto efi_main_error;
465 	}
466 
467 	/* Set up arch-specific resources */
468 	status = setup_efi(&efi_bootinfo);
469 	if (status != EFI_SUCCESS) {
470 		printf("Failed to set up arch-specific resources\n");
471 		goto efi_main_error;
472 	}
473 
474 	printf("Address of image is: 0x%lx\n", (unsigned long)&_text);
475 
476 	/* Run the test case */
477 	ret = main(__argc, __argv, __environ);
478 
479 	/* Shutdown the guest VM */
480 	efi_exit(ret);
481 
482 	/* Unreachable */
483 	return EFI_UNSUPPORTED;
484 
485 efi_main_error:
486 	/* Shutdown the guest with error EFI status */
487 	efi_exit(status);
488 
489 	/* Unreachable */
490 	return EFI_UNSUPPORTED;
491 }
492