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, struct efi_boot_memmap *map) 69 { 70 return efi_bs_call(exit_boot_services, handle, *map->key_ptr); 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 static void efi_exit(efi_status_t code) 89 { 90 exit(code); 91 92 /* 93 * Fallback to UEFI reset_system() service, in case testdev is 94 * missing and exit() does not properly exit. 95 */ 96 efi_rs_call(reset_system, EFI_RESET_SHUTDOWN, code, 0, NULL); 97 } 98 99 efi_status_t efi_main(efi_handle_t handle, efi_system_table_t *sys_tab) 100 { 101 int ret; 102 efi_status_t status; 103 efi_bootinfo_t efi_bootinfo; 104 105 efi_system_table = sys_tab; 106 107 /* Memory map struct values */ 108 efi_memory_desc_t *map = NULL; 109 unsigned long map_size = 0, desc_size = 0, key = 0, buff_size = 0; 110 u32 desc_ver; 111 112 /* Set up efi_bootinfo */ 113 efi_bootinfo.mem_map.map = ↦ 114 efi_bootinfo.mem_map.map_size = &map_size; 115 efi_bootinfo.mem_map.desc_size = &desc_size; 116 efi_bootinfo.mem_map.desc_ver = &desc_ver; 117 efi_bootinfo.mem_map.key_ptr = &key; 118 efi_bootinfo.mem_map.buff_size = &buff_size; 119 120 /* Get EFI memory map */ 121 status = efi_get_memory_map(&efi_bootinfo.mem_map); 122 if (status != EFI_SUCCESS) { 123 printf("Failed to get memory map\n"); 124 goto efi_main_error; 125 } 126 127 /* 128 * Exit EFI boot services, let kvm-unit-tests take full control of the 129 * guest 130 */ 131 status = efi_exit_boot_services(handle, &efi_bootinfo.mem_map); 132 if (status != EFI_SUCCESS) { 133 printf("Failed to exit boot services\n"); 134 goto efi_main_error; 135 } 136 137 /* Set up arch-specific resources */ 138 status = setup_efi(&efi_bootinfo); 139 if (status != EFI_SUCCESS) { 140 printf("Failed to set up arch-specific resources\n"); 141 goto efi_main_error; 142 } 143 144 /* Run the test case */ 145 ret = main(__argc, __argv, __environ); 146 147 /* Shutdown the guest VM */ 148 efi_exit(ret); 149 150 /* Unreachable */ 151 return EFI_UNSUPPORTED; 152 153 efi_main_error: 154 /* Shutdown the guest with error EFI status */ 155 efi_exit(status); 156 157 /* Unreachable */ 158 return EFI_UNSUPPORTED; 159 } 160