xref: /kvm-unit-tests/lib/efi.c (revision 25ef5154148bee2949b3593dce0575525f26a321)
10eaa5176SVarad Gautam /*
20eaa5176SVarad Gautam  * EFI-related functions to set up and run test cases in EFI
30eaa5176SVarad Gautam  *
40eaa5176SVarad Gautam  * Copyright (c) 2021, SUSE, Varad Gautam <varad.gautam@suse.com>
5ad5fb883SZixuan Wang  * Copyright (c) 2021, Google Inc, Zixuan Wang <zixuanwang@google.com>
60eaa5176SVarad Gautam  *
70eaa5176SVarad Gautam  * SPDX-License-Identifier: LGPL-2.0-or-later
80eaa5176SVarad Gautam  */
90eaa5176SVarad Gautam 
10ad5fb883SZixuan Wang #include "efi.h"
1185c3c524SNikos Nikoleris #include <argv.h>
1285c3c524SNikos Nikoleris #include <stdlib.h>
1385c3c524SNikos Nikoleris #include <ctype.h>
14ad5fb883SZixuan Wang #include <libcflat.h>
15ad5fb883SZixuan Wang #include <asm/setup.h>
16ad5fb883SZixuan Wang 
17ad5fb883SZixuan Wang /* From lib/argv.c */
18ad5fb883SZixuan Wang extern int __argc, __envc;
19ad5fb883SZixuan Wang extern char *__argv[100];
20ad5fb883SZixuan Wang extern char *__environ[200];
21ad5fb883SZixuan Wang 
22*25ef5154SNadav Amit extern char _text;
23*25ef5154SNadav Amit 
24ad5fb883SZixuan Wang extern int main(int argc, char **argv, char **envp);
25ad5fb883SZixuan Wang 
260eaa5176SVarad Gautam efi_system_table_t *efi_system_table = NULL;
270eaa5176SVarad Gautam 
280eaa5176SVarad Gautam static void efi_free_pool(void *ptr)
290eaa5176SVarad Gautam {
300eaa5176SVarad Gautam 	efi_bs_call(free_pool, ptr);
310eaa5176SVarad Gautam }
320eaa5176SVarad Gautam 
33ad5fb883SZixuan Wang efi_status_t efi_get_memory_map(struct efi_boot_memmap *map)
340eaa5176SVarad Gautam {
350eaa5176SVarad Gautam 	efi_memory_desc_t *m = NULL;
360eaa5176SVarad Gautam 	efi_status_t status;
370eaa5176SVarad Gautam 	unsigned long key = 0, map_size = 0, desc_size = 0;
381ae9072eSZixuan Wang 	u32 desc_ver;
390eaa5176SVarad Gautam 
400eaa5176SVarad Gautam 	status = efi_bs_call(get_memory_map, &map_size,
411ae9072eSZixuan Wang 			     NULL, &key, &desc_size, &desc_ver);
420eaa5176SVarad Gautam 	if (status != EFI_BUFFER_TOO_SMALL || map_size == 0)
430eaa5176SVarad Gautam 		goto out;
440eaa5176SVarad Gautam 
450eaa5176SVarad Gautam 	/*
460eaa5176SVarad Gautam 	 * Pad map_size with additional descriptors so we don't need to
470eaa5176SVarad Gautam 	 * retry.
480eaa5176SVarad Gautam 	 */
490eaa5176SVarad Gautam 	map_size += 4 * desc_size;
500eaa5176SVarad Gautam 	*map->buff_size = map_size;
510eaa5176SVarad Gautam 	status = efi_bs_call(allocate_pool, EFI_LOADER_DATA,
520eaa5176SVarad Gautam 			     map_size, (void **)&m);
530eaa5176SVarad Gautam 	if (status != EFI_SUCCESS)
540eaa5176SVarad Gautam 		goto out;
550eaa5176SVarad Gautam 
560eaa5176SVarad Gautam 	/* Get the map. */
570eaa5176SVarad Gautam 	status = efi_bs_call(get_memory_map, &map_size,
581ae9072eSZixuan Wang 			     m, &key, &desc_size, &desc_ver);
590eaa5176SVarad Gautam 	if (status != EFI_SUCCESS) {
600eaa5176SVarad Gautam 		efi_free_pool(m);
610eaa5176SVarad Gautam 		goto out;
620eaa5176SVarad Gautam 	}
630eaa5176SVarad Gautam 
641ae9072eSZixuan Wang 	*map->desc_ver = desc_ver;
650eaa5176SVarad Gautam 	*map->desc_size = desc_size;
660eaa5176SVarad Gautam 	*map->map_size = map_size;
670eaa5176SVarad Gautam 	*map->key_ptr = key;
680eaa5176SVarad Gautam out:
690eaa5176SVarad Gautam 	*map->map = m;
700eaa5176SVarad Gautam 	return status;
710eaa5176SVarad Gautam }
720eaa5176SVarad Gautam 
73b4e8c300SZixuan Wang efi_status_t efi_exit_boot_services(void *handle, struct efi_boot_memmap *map)
740eaa5176SVarad Gautam {
75b4e8c300SZixuan Wang 	return efi_bs_call(exit_boot_services, handle, *map->key_ptr);
760eaa5176SVarad Gautam }
770eaa5176SVarad Gautam 
78f20589d6SZixuan Wang efi_status_t efi_get_system_config_table(efi_guid_t table_guid, void **table)
79f20589d6SZixuan Wang {
80f20589d6SZixuan Wang 	size_t i;
81f20589d6SZixuan Wang 	efi_config_table_t *tables;
82f20589d6SZixuan Wang 
83f20589d6SZixuan Wang 	tables = (efi_config_table_t *)efi_system_table->tables;
84f20589d6SZixuan Wang 	for (i = 0; i < efi_system_table->nr_tables; i++) {
85f20589d6SZixuan Wang 		if (!memcmp(&table_guid, &tables[i].guid, sizeof(efi_guid_t))) {
86f20589d6SZixuan Wang 			*table = tables[i].table;
87f20589d6SZixuan Wang 			return EFI_SUCCESS;
88f20589d6SZixuan Wang 		}
89f20589d6SZixuan Wang 	}
90f20589d6SZixuan Wang 	return EFI_NOT_FOUND;
91f20589d6SZixuan Wang }
92f20589d6SZixuan Wang 
932f47d025SZixuan Wang static void efi_exit(efi_status_t code)
942f47d025SZixuan Wang {
952f47d025SZixuan Wang 	exit(code);
962f47d025SZixuan Wang 
972f47d025SZixuan Wang 	/*
982f47d025SZixuan Wang 	 * Fallback to UEFI reset_system() service, in case testdev is
992f47d025SZixuan Wang 	 * missing and exit() does not properly exit.
1002f47d025SZixuan Wang 	 */
1012f47d025SZixuan Wang 	efi_rs_call(reset_system, EFI_RESET_SHUTDOWN, code, 0, NULL);
1022f47d025SZixuan Wang }
1032f47d025SZixuan Wang 
10485c3c524SNikos Nikoleris /* Adapted from drivers/firmware/efi/libstub/efi-stub.c */
10585c3c524SNikos Nikoleris static char *efi_convert_cmdline(struct efi_loaded_image_64 *image, int *cmd_line_len)
10685c3c524SNikos Nikoleris {
10785c3c524SNikos Nikoleris 	const u16 *s2;
10885c3c524SNikos Nikoleris 	unsigned long cmdline_addr = 0;
10985c3c524SNikos Nikoleris 	int options_chars = image->load_options_size;
11085c3c524SNikos Nikoleris 	const u16 *options = image->load_options;
11185c3c524SNikos Nikoleris 	int options_bytes = 0, safe_options_bytes = 0;  /* UTF-8 bytes */
11285c3c524SNikos Nikoleris 	bool in_quote = false;
11385c3c524SNikos Nikoleris 	efi_status_t status;
11485c3c524SNikos Nikoleris 	const int COMMAND_LINE_SIZE = 2048;
11585c3c524SNikos Nikoleris 
11685c3c524SNikos Nikoleris 	if (options) {
11785c3c524SNikos Nikoleris 		s2 = options;
11885c3c524SNikos Nikoleris 		while (options_bytes < COMMAND_LINE_SIZE && options_chars--) {
11985c3c524SNikos Nikoleris 			u16 c = *s2++;
12085c3c524SNikos Nikoleris 
12185c3c524SNikos Nikoleris 			if (c < 0x80) {
12285c3c524SNikos Nikoleris 				if (c == L'\0' || c == L'\n')
12385c3c524SNikos Nikoleris 					break;
12485c3c524SNikos Nikoleris 				if (c == L'"')
12585c3c524SNikos Nikoleris 					in_quote = !in_quote;
12685c3c524SNikos Nikoleris 				else if (!in_quote && isspace((char)c))
12785c3c524SNikos Nikoleris 					safe_options_bytes = options_bytes;
12885c3c524SNikos Nikoleris 
12985c3c524SNikos Nikoleris 				options_bytes++;
13085c3c524SNikos Nikoleris 				continue;
13185c3c524SNikos Nikoleris 			}
13285c3c524SNikos Nikoleris 
13385c3c524SNikos Nikoleris 			/*
13485c3c524SNikos Nikoleris 			 * Get the number of UTF-8 bytes corresponding to a
13585c3c524SNikos Nikoleris 			 * UTF-16 character.
13685c3c524SNikos Nikoleris 			 * The first part handles everything in the BMP.
13785c3c524SNikos Nikoleris 			 */
13885c3c524SNikos Nikoleris 			options_bytes += 2 + (c >= 0x800);
13985c3c524SNikos Nikoleris 			/*
14085c3c524SNikos Nikoleris 			 * Add one more byte for valid surrogate pairs. Invalid
14185c3c524SNikos Nikoleris 			 * surrogates will be replaced with 0xfffd and take up
14285c3c524SNikos Nikoleris 			 * only 3 bytes.
14385c3c524SNikos Nikoleris 			 */
14485c3c524SNikos Nikoleris 			if ((c & 0xfc00) == 0xd800) {
14585c3c524SNikos Nikoleris 				/*
14685c3c524SNikos Nikoleris 				 * If the very last word is a high surrogate,
14785c3c524SNikos Nikoleris 				 * we must ignore it since we can't access the
14885c3c524SNikos Nikoleris 				 * low surrogate.
14985c3c524SNikos Nikoleris 				 */
15085c3c524SNikos Nikoleris 				if (!options_chars) {
15185c3c524SNikos Nikoleris 					options_bytes -= 3;
15285c3c524SNikos Nikoleris 				} else if ((*s2 & 0xfc00) == 0xdc00) {
15385c3c524SNikos Nikoleris 					options_bytes++;
15485c3c524SNikos Nikoleris 					options_chars--;
15585c3c524SNikos Nikoleris 					s2++;
15685c3c524SNikos Nikoleris 				}
15785c3c524SNikos Nikoleris 			}
15885c3c524SNikos Nikoleris 		}
15985c3c524SNikos Nikoleris 		if (options_bytes >= COMMAND_LINE_SIZE) {
16085c3c524SNikos Nikoleris 			options_bytes = safe_options_bytes;
16185c3c524SNikos Nikoleris 			printf("Command line is too long: truncated to %d bytes\n",
16285c3c524SNikos Nikoleris 			       options_bytes);
16385c3c524SNikos Nikoleris 		}
16485c3c524SNikos Nikoleris 	}
16585c3c524SNikos Nikoleris 
16685c3c524SNikos Nikoleris 	options_bytes++;        /* NUL termination */
16785c3c524SNikos Nikoleris 
16885c3c524SNikos Nikoleris 	status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, options_bytes, (void **)&cmdline_addr);
16985c3c524SNikos Nikoleris 	if (status != EFI_SUCCESS)
17085c3c524SNikos Nikoleris 		return NULL;
17185c3c524SNikos Nikoleris 
17285c3c524SNikos Nikoleris 	snprintf((char *)cmdline_addr, options_bytes, "%.*ls", options_bytes - 1, options);
17385c3c524SNikos Nikoleris 
17485c3c524SNikos Nikoleris 	*cmd_line_len = options_bytes;
17585c3c524SNikos Nikoleris 	return (char *)cmdline_addr;
17685c3c524SNikos Nikoleris }
17785c3c524SNikos Nikoleris 
178529ab889SNikos Nikoleris /*
179529ab889SNikos Nikoleris  * Open the file and read it into a buffer.
180529ab889SNikos Nikoleris  */
181529ab889SNikos Nikoleris static void efi_load_image(efi_handle_t handle, struct efi_loaded_image_64 *image, void **data,
182529ab889SNikos Nikoleris 			   int *datasize, efi_char16_t *path_name)
183529ab889SNikos Nikoleris {
184529ab889SNikos Nikoleris 	uint64_t buffer_size = sizeof(efi_file_info_t);
185529ab889SNikos Nikoleris 	efi_file_info_t *file_info;
186529ab889SNikos Nikoleris 	efi_file_io_interface_t *io_if;
187529ab889SNikos Nikoleris 	efi_file_t *root, *file;
188529ab889SNikos Nikoleris 	efi_status_t status;
189529ab889SNikos Nikoleris 	efi_guid_t file_system_proto_guid = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID;
190529ab889SNikos Nikoleris 	efi_guid_t file_info_guid = EFI_FILE_INFO_ID;
191529ab889SNikos Nikoleris 
192529ab889SNikos Nikoleris 	/* Open the device */
193529ab889SNikos Nikoleris 	status = efi_bs_call(handle_protocol, image->device_handle, &file_system_proto_guid,
194529ab889SNikos Nikoleris 			     (void **)&io_if);
195529ab889SNikos Nikoleris 	if (status != EFI_SUCCESS)
196529ab889SNikos Nikoleris 		return;
197529ab889SNikos Nikoleris 
198529ab889SNikos Nikoleris 	status = io_if->open_volume(io_if, &root);
199529ab889SNikos Nikoleris 	if (status != EFI_SUCCESS)
200529ab889SNikos Nikoleris 		return;
201529ab889SNikos Nikoleris 
202529ab889SNikos Nikoleris 	/* And then open the file */
203529ab889SNikos Nikoleris 	status = root->open(root, &file, path_name, EFI_FILE_MODE_READ, 0);
204529ab889SNikos Nikoleris 	if (status != EFI_SUCCESS) {
205529ab889SNikos Nikoleris 		printf("Failed to open %ls - %lx\n", path_name, status);
206529ab889SNikos Nikoleris 		assert(status == EFI_SUCCESS);
207529ab889SNikos Nikoleris 	}
208529ab889SNikos Nikoleris 
209529ab889SNikos Nikoleris 	/* Find the file size in order to allocate the buffer */
210529ab889SNikos Nikoleris 	status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, buffer_size, (void **)&file_info);
211529ab889SNikos Nikoleris 	if (status != EFI_SUCCESS)
212529ab889SNikos Nikoleris 		return;
213529ab889SNikos Nikoleris 
214529ab889SNikos Nikoleris 	status = file->get_info(file, &file_info_guid, &buffer_size, file_info);
215529ab889SNikos Nikoleris 	if (status == EFI_BUFFER_TOO_SMALL) {
216529ab889SNikos Nikoleris 		efi_free_pool(file_info);
217529ab889SNikos Nikoleris 		status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, buffer_size, (void **)&file_info);
218529ab889SNikos Nikoleris 		assert(file_info);
219529ab889SNikos Nikoleris 		status = file->get_info(file, &file_info_guid, &buffer_size, file_info);
220529ab889SNikos Nikoleris 	}
221529ab889SNikos Nikoleris 	assert(status == EFI_SUCCESS);
222529ab889SNikos Nikoleris 
223529ab889SNikos Nikoleris 	buffer_size = file_info->file_size;
224529ab889SNikos Nikoleris 
225529ab889SNikos Nikoleris 	efi_free_pool(file_info);
226529ab889SNikos Nikoleris 
227529ab889SNikos Nikoleris 	status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, buffer_size, (void **)data);
228529ab889SNikos Nikoleris 	assert(*data);
229529ab889SNikos Nikoleris 	/* Perform the actual read */
230529ab889SNikos Nikoleris 	status = file->read(file, &buffer_size, *data);
231529ab889SNikos Nikoleris 	if (status == EFI_BUFFER_TOO_SMALL) {
232529ab889SNikos Nikoleris 		efi_free_pool(*data);
233529ab889SNikos Nikoleris 		status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, buffer_size, (void **)data);
234529ab889SNikos Nikoleris 		status = file->read(file, &buffer_size, *data);
235529ab889SNikos Nikoleris 	}
236529ab889SNikos Nikoleris 	assert(status == EFI_SUCCESS);
237529ab889SNikos Nikoleris 
238529ab889SNikos Nikoleris 	*datasize = buffer_size;
239529ab889SNikos Nikoleris }
240529ab889SNikos Nikoleris 
241529ab889SNikos Nikoleris static int efi_grow_buffer(efi_status_t *status, void **buffer, uint64_t buffer_size)
242529ab889SNikos Nikoleris {
243529ab889SNikos Nikoleris 	int try_again;
244529ab889SNikos Nikoleris 
245529ab889SNikos Nikoleris 	if (!*buffer && buffer_size) {
246529ab889SNikos Nikoleris 		*status = EFI_BUFFER_TOO_SMALL;
247529ab889SNikos Nikoleris 	}
248529ab889SNikos Nikoleris 
249529ab889SNikos Nikoleris 	try_again = 0;
250529ab889SNikos Nikoleris 	if (*status == EFI_BUFFER_TOO_SMALL) {
251529ab889SNikos Nikoleris 		if (*buffer)
252529ab889SNikos Nikoleris 			efi_free_pool(*buffer);
253529ab889SNikos Nikoleris 
254529ab889SNikos Nikoleris 		efi_bs_call(allocate_pool, EFI_LOADER_DATA, buffer_size, buffer);
255529ab889SNikos Nikoleris 		if (*buffer) {
256529ab889SNikos Nikoleris 			try_again = 1;
257529ab889SNikos Nikoleris 		} else {
258529ab889SNikos Nikoleris 			*status = EFI_OUT_OF_RESOURCES;
259529ab889SNikos Nikoleris 		}
260529ab889SNikos Nikoleris 	}
261529ab889SNikos Nikoleris 
262529ab889SNikos Nikoleris 	if (!try_again && EFI_ERROR(*status) && *buffer) {
263529ab889SNikos Nikoleris 		efi_free_pool(*buffer);
264529ab889SNikos Nikoleris 		*buffer = NULL;
265529ab889SNikos Nikoleris 	}
266529ab889SNikos Nikoleris 
267529ab889SNikos Nikoleris 	return try_again;
268529ab889SNikos Nikoleris }
269529ab889SNikos Nikoleris 
270529ab889SNikos Nikoleris static void* efi_get_var(efi_handle_t handle, struct efi_loaded_image_64 *image, efi_char16_t *var)
271529ab889SNikos Nikoleris {
272529ab889SNikos Nikoleris 	efi_status_t status = EFI_SUCCESS;
273529ab889SNikos Nikoleris 	void *val = NULL;
274529ab889SNikos Nikoleris 	uint64_t val_size = 100;
275529ab889SNikos Nikoleris 	efi_guid_t efi_var_guid = EFI_VAR_GUID;
276529ab889SNikos Nikoleris 
277529ab889SNikos Nikoleris 	while (efi_grow_buffer(&status, &val, val_size + sizeof(efi_char16_t)))
278529ab889SNikos Nikoleris 		status = efi_rs_call(get_variable, var, &efi_var_guid, NULL, &val_size, val);
279529ab889SNikos Nikoleris 
280529ab889SNikos Nikoleris 	if (val)
281529ab889SNikos Nikoleris 		((efi_char16_t *)val)[val_size / sizeof(efi_char16_t)] = L'\0';
282529ab889SNikos Nikoleris 
283529ab889SNikos Nikoleris 	return val;
284529ab889SNikos Nikoleris }
285529ab889SNikos Nikoleris 
286529ab889SNikos Nikoleris static void *efi_get_fdt(efi_handle_t handle, struct efi_loaded_image_64 *image)
287529ab889SNikos Nikoleris {
288529ab889SNikos Nikoleris 	efi_char16_t var[] = ENV_VARNAME_DTBFILE;
289529ab889SNikos Nikoleris 	efi_char16_t *val;
290529ab889SNikos Nikoleris 	void *fdt = NULL;
291529ab889SNikos Nikoleris 	int fdtsize;
292529ab889SNikos Nikoleris 
293529ab889SNikos Nikoleris 	val = efi_get_var(handle, image, var);
294529ab889SNikos Nikoleris 	if (val)
295529ab889SNikos Nikoleris 		efi_load_image(handle, image, &fdt, &fdtsize, val);
296529ab889SNikos Nikoleris 
297529ab889SNikos Nikoleris 	return fdt;
298529ab889SNikos Nikoleris }
299529ab889SNikos Nikoleris 
300ad5fb883SZixuan Wang efi_status_t efi_main(efi_handle_t handle, efi_system_table_t *sys_tab)
3010eaa5176SVarad Gautam {
302ad5fb883SZixuan Wang 	int ret;
3031ae9072eSZixuan Wang 	efi_status_t status;
3041ae9072eSZixuan Wang 	efi_bootinfo_t efi_bootinfo;
305ad5fb883SZixuan Wang 
3060eaa5176SVarad Gautam 	efi_system_table = sys_tab;
3070eaa5176SVarad Gautam 
308b4e8c300SZixuan Wang 	/* Memory map struct values */
309b4e8c300SZixuan Wang 	efi_memory_desc_t *map = NULL;
310b4e8c300SZixuan Wang 	unsigned long map_size = 0, desc_size = 0, key = 0, buff_size = 0;
311b4e8c300SZixuan Wang 	u32 desc_ver;
312b4e8c300SZixuan Wang 
31385c3c524SNikos Nikoleris 	/* Helper variables needed to get the cmdline */
31485c3c524SNikos Nikoleris 	struct efi_loaded_image_64 *image;
31585c3c524SNikos Nikoleris 	efi_guid_t loaded_image_proto = LOADED_IMAGE_PROTOCOL_GUID;
31685c3c524SNikos Nikoleris 	char *cmdline_ptr = NULL;
31785c3c524SNikos Nikoleris 	int cmdline_size = 0;
31885c3c524SNikos Nikoleris 
31985c3c524SNikos Nikoleris 	/*
32085c3c524SNikos Nikoleris 	 * Get a handle to the loaded image protocol.  This is used to get
32185c3c524SNikos Nikoleris 	 * information about the running image, such as size and the command
32285c3c524SNikos Nikoleris 	 * line.
32385c3c524SNikos Nikoleris 	 */
32485c3c524SNikos Nikoleris 	status = efi_bs_call(handle_protocol, handle, &loaded_image_proto, (void *)&image);
32585c3c524SNikos Nikoleris 	if (status != EFI_SUCCESS) {
32685c3c524SNikos Nikoleris 		printf("Failed to get loaded image protocol\n");
32785c3c524SNikos Nikoleris 		goto efi_main_error;
32885c3c524SNikos Nikoleris 	}
32985c3c524SNikos Nikoleris 
33085c3c524SNikos Nikoleris 	cmdline_ptr = efi_convert_cmdline(image, &cmdline_size);
33185c3c524SNikos Nikoleris 	if (!cmdline_ptr) {
33285c3c524SNikos Nikoleris 		printf("getting command line via LOADED_IMAGE_PROTOCOL\n");
33385c3c524SNikos Nikoleris 		status = EFI_OUT_OF_RESOURCES;
33485c3c524SNikos Nikoleris 		goto efi_main_error;
33585c3c524SNikos Nikoleris 	}
33685c3c524SNikos Nikoleris 	setup_args(cmdline_ptr);
33785c3c524SNikos Nikoleris 
338529ab889SNikos Nikoleris 	efi_bootinfo.fdt = efi_get_fdt(handle, image);
339b4e8c300SZixuan Wang 	/* Set up efi_bootinfo */
340b4e8c300SZixuan Wang 	efi_bootinfo.mem_map.map = &map;
341b4e8c300SZixuan Wang 	efi_bootinfo.mem_map.map_size = &map_size;
342b4e8c300SZixuan Wang 	efi_bootinfo.mem_map.desc_size = &desc_size;
343b4e8c300SZixuan Wang 	efi_bootinfo.mem_map.desc_ver = &desc_ver;
344b4e8c300SZixuan Wang 	efi_bootinfo.mem_map.key_ptr = &key;
345b4e8c300SZixuan Wang 	efi_bootinfo.mem_map.buff_size = &buff_size;
346b4e8c300SZixuan Wang 
347b4e8c300SZixuan Wang 	/* Get EFI memory map */
348b4e8c300SZixuan Wang 	status = efi_get_memory_map(&efi_bootinfo.mem_map);
3491ae9072eSZixuan Wang 	if (status != EFI_SUCCESS) {
350b4e8c300SZixuan Wang 		printf("Failed to get memory map\n");
351b4e8c300SZixuan Wang 		goto efi_main_error;
3521ae9072eSZixuan Wang 	}
3531ae9072eSZixuan Wang 
354b4e8c300SZixuan Wang 	/*
355b4e8c300SZixuan Wang 	 * Exit EFI boot services, let kvm-unit-tests take full control of the
356b4e8c300SZixuan Wang 	 * guest
357b4e8c300SZixuan Wang 	 */
358b4e8c300SZixuan Wang 	status = efi_exit_boot_services(handle, &efi_bootinfo.mem_map);
3591ae9072eSZixuan Wang 	if (status != EFI_SUCCESS) {
3601ae9072eSZixuan Wang 		printf("Failed to exit boot services\n");
361b4e8c300SZixuan Wang 		goto efi_main_error;
3621ae9072eSZixuan Wang 	}
3631ae9072eSZixuan Wang 
364b4e8c300SZixuan Wang 	/* Set up arch-specific resources */
365b4e8c300SZixuan Wang 	status = setup_efi(&efi_bootinfo);
366b4e8c300SZixuan Wang 	if (status != EFI_SUCCESS) {
367b4e8c300SZixuan Wang 		printf("Failed to set up arch-specific resources\n");
368b4e8c300SZixuan Wang 		goto efi_main_error;
369b4e8c300SZixuan Wang 	}
370b4e8c300SZixuan Wang 
371*25ef5154SNadav Amit 	printf("Address of image is: 0x%lx\n", (unsigned long)&_text);
372*25ef5154SNadav Amit 
373b4e8c300SZixuan Wang 	/* Run the test case */
374ad5fb883SZixuan Wang 	ret = main(__argc, __argv, __environ);
375ad5fb883SZixuan Wang 
3762f47d025SZixuan Wang 	/* Shutdown the guest VM */
3772f47d025SZixuan Wang 	efi_exit(ret);
378ad5fb883SZixuan Wang 
379ad5fb883SZixuan Wang 	/* Unreachable */
380ad5fb883SZixuan Wang 	return EFI_UNSUPPORTED;
381b4e8c300SZixuan Wang 
382b4e8c300SZixuan Wang efi_main_error:
383b4e8c300SZixuan Wang 	/* Shutdown the guest with error EFI status */
3842f47d025SZixuan Wang 	efi_exit(status);
385b4e8c300SZixuan Wang 
386b4e8c300SZixuan Wang 	/* Unreachable */
387b4e8c300SZixuan Wang 	return EFI_UNSUPPORTED;
3880eaa5176SVarad Gautam }
389