xref: /kvm-unit-tests/lib/efi.c (revision f20589d6e047e5ca72664fc63a18acb129feb53f)
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 
10 #include "efi.h"
11 #include <libcflat.h>
12 #include <asm/setup.h>
13 
14 /* From lib/argv.c */
15 extern int __argc, __envc;
16 extern char *__argv[100];
17 extern char *__environ[200];
18 
19 extern int main(int argc, char **argv, char **envp);
20 
21 efi_system_table_t *efi_system_table = NULL;
22 
23 static void efi_free_pool(void *ptr)
24 {
25 	efi_bs_call(free_pool, ptr);
26 }
27 
28 efi_status_t efi_get_memory_map(struct efi_boot_memmap *map)
29 {
30 	efi_memory_desc_t *m = NULL;
31 	efi_status_t status;
32 	unsigned long key = 0, map_size = 0, desc_size = 0;
33 	u32 desc_ver;
34 
35 	status = efi_bs_call(get_memory_map, &map_size,
36 			     NULL, &key, &desc_size, &desc_ver);
37 	if (status != EFI_BUFFER_TOO_SMALL || map_size == 0)
38 		goto out;
39 
40 	/*
41 	 * Pad map_size with additional descriptors so we don't need to
42 	 * retry.
43 	 */
44 	map_size += 4 * desc_size;
45 	*map->buff_size = map_size;
46 	status = efi_bs_call(allocate_pool, EFI_LOADER_DATA,
47 			     map_size, (void **)&m);
48 	if (status != EFI_SUCCESS)
49 		goto out;
50 
51 	/* Get the map. */
52 	status = efi_bs_call(get_memory_map, &map_size,
53 			     m, &key, &desc_size, &desc_ver);
54 	if (status != EFI_SUCCESS) {
55 		efi_free_pool(m);
56 		goto out;
57 	}
58 
59 	*map->desc_ver = desc_ver;
60 	*map->desc_size = desc_size;
61 	*map->map_size = map_size;
62 	*map->key_ptr = key;
63 out:
64 	*map->map = m;
65 	return status;
66 }
67 
68 efi_status_t efi_exit_boot_services(void *handle, unsigned long mapkey)
69 {
70 	return efi_bs_call(exit_boot_services, handle, mapkey);
71 }
72 
73 efi_status_t efi_get_system_config_table(efi_guid_t table_guid, void **table)
74 {
75 	size_t i;
76 	efi_config_table_t *tables;
77 
78 	tables = (efi_config_table_t *)efi_system_table->tables;
79 	for (i = 0; i < efi_system_table->nr_tables; i++) {
80 		if (!memcmp(&table_guid, &tables[i].guid, sizeof(efi_guid_t))) {
81 			*table = tables[i].table;
82 			return EFI_SUCCESS;
83 		}
84 	}
85 	return EFI_NOT_FOUND;
86 }
87 
88 efi_status_t efi_main(efi_handle_t handle, efi_system_table_t *sys_tab)
89 {
90 	int ret;
91 	unsigned long mapkey = 0;
92 	efi_status_t status;
93 	efi_bootinfo_t efi_bootinfo;
94 
95 	efi_system_table = sys_tab;
96 
97 	setup_efi_bootinfo(&efi_bootinfo);
98 	status = setup_efi_pre_boot(&mapkey, &efi_bootinfo);
99 	if (status != EFI_SUCCESS) {
100 		printf("Failed to set up before ExitBootServices, exiting.\n");
101 		return status;
102 	}
103 
104 	status = efi_exit_boot_services(handle, mapkey);
105 	if (status != EFI_SUCCESS) {
106 		printf("Failed to exit boot services\n");
107 		return status;
108 	}
109 
110 	setup_efi(&efi_bootinfo);
111 	ret = main(__argc, __argv, __environ);
112 	exit(ret);
113 
114 	/* Shutdown the guest VM in case exit() fails */
115 	efi_rs_call(reset_system, EFI_RESET_SHUTDOWN, ret, 0, NULL);
116 
117 	/* Unreachable */
118 	return EFI_UNSUPPORTED;
119 }
120