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 = ↦ 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