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 */ 9ad5fb883SZixuan Wang #include <libcflat.h> 109632ce44SAndrew Jones #include <argv.h> 119632ce44SAndrew Jones #include <ctype.h> 129632ce44SAndrew Jones #include <stdlib.h> 13ad5fb883SZixuan Wang #include <asm/setup.h> 149632ce44SAndrew Jones #include "efi.h" 159632ce44SAndrew Jones #include "libfdt/libfdt.h" 16ad5fb883SZixuan Wang 17b9f8ff7cSAndrew Jones /* From each arch */ 18b9f8ff7cSAndrew Jones extern char *initrd; 19b9f8ff7cSAndrew Jones extern u32 initrd_size; 20b9f8ff7cSAndrew Jones 21ad5fb883SZixuan Wang /* From lib/argv.c */ 22ad5fb883SZixuan Wang extern int __argc, __envc; 23ad5fb883SZixuan Wang extern char *__argv[100]; 24ad5fb883SZixuan Wang extern char *__environ[200]; 25ad5fb883SZixuan Wang 2625ef5154SNadav Amit extern char _text; 2725ef5154SNadav Amit 28ad5fb883SZixuan Wang extern int main(int argc, char **argv, char **envp); 29ad5fb883SZixuan Wang 300eaa5176SVarad Gautam efi_system_table_t *efi_system_table = NULL; 310eaa5176SVarad Gautam 32ba0a6fd4SAndrew Jones #ifdef __riscv 33ba0a6fd4SAndrew Jones #define RISCV_EFI_BOOT_PROTOCOL_GUID EFI_GUID(0xccd15fec, 0x6f73, 0x4eec, 0x83, 0x95, 0x3e, 0x69, 0xe4, 0xb9, 0x40, 0xbf) 34ba0a6fd4SAndrew Jones 35ba0a6fd4SAndrew Jones unsigned long boot_hartid; 36ba0a6fd4SAndrew Jones 37ba0a6fd4SAndrew Jones struct riscv_efi_boot_protocol { 38ba0a6fd4SAndrew Jones u64 revision; 39ba0a6fd4SAndrew Jones efi_status_t (*get_boot_hartid)(struct riscv_efi_boot_protocol *, 40ba0a6fd4SAndrew Jones unsigned long *boot_hartid); 41ba0a6fd4SAndrew Jones }; 42ba0a6fd4SAndrew Jones 43ba0a6fd4SAndrew Jones static efi_status_t efi_get_boot_hartid(void) 44ba0a6fd4SAndrew Jones { 45ba0a6fd4SAndrew Jones efi_guid_t boot_protocol_guid = RISCV_EFI_BOOT_PROTOCOL_GUID; 46ba0a6fd4SAndrew Jones struct riscv_efi_boot_protocol *boot_protocol; 47ba0a6fd4SAndrew Jones efi_status_t status; 48ba0a6fd4SAndrew Jones 49ba0a6fd4SAndrew Jones status = efi_bs_call(locate_protocol, &boot_protocol_guid, NULL, 50ba0a6fd4SAndrew Jones (void **)&boot_protocol); 51ba0a6fd4SAndrew Jones if (status != EFI_SUCCESS) 52ba0a6fd4SAndrew Jones return status; 53ba0a6fd4SAndrew Jones return efi_call_proto(boot_protocol, get_boot_hartid, &boot_hartid); 54ba0a6fd4SAndrew Jones } 55ba0a6fd4SAndrew Jones #endif 56ba0a6fd4SAndrew Jones 570eaa5176SVarad Gautam static void efi_free_pool(void *ptr) 580eaa5176SVarad Gautam { 590eaa5176SVarad Gautam efi_bs_call(free_pool, ptr); 600eaa5176SVarad Gautam } 610eaa5176SVarad Gautam 62ad5fb883SZixuan Wang efi_status_t efi_get_memory_map(struct efi_boot_memmap *map) 630eaa5176SVarad Gautam { 640eaa5176SVarad Gautam efi_memory_desc_t *m = NULL; 650eaa5176SVarad Gautam efi_status_t status; 660eaa5176SVarad Gautam unsigned long key = 0, map_size = 0, desc_size = 0; 671ae9072eSZixuan Wang u32 desc_ver; 680eaa5176SVarad Gautam 690eaa5176SVarad Gautam status = efi_bs_call(get_memory_map, &map_size, 701ae9072eSZixuan Wang NULL, &key, &desc_size, &desc_ver); 710eaa5176SVarad Gautam if (status != EFI_BUFFER_TOO_SMALL || map_size == 0) 720eaa5176SVarad Gautam goto out; 730eaa5176SVarad Gautam 740eaa5176SVarad Gautam /* 750eaa5176SVarad Gautam * Pad map_size with additional descriptors so we don't need to 760eaa5176SVarad Gautam * retry. 770eaa5176SVarad Gautam */ 780eaa5176SVarad Gautam map_size += 4 * desc_size; 790eaa5176SVarad Gautam *map->buff_size = map_size; 800eaa5176SVarad Gautam status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, 810eaa5176SVarad Gautam map_size, (void **)&m); 820eaa5176SVarad Gautam if (status != EFI_SUCCESS) 830eaa5176SVarad Gautam goto out; 840eaa5176SVarad Gautam 850eaa5176SVarad Gautam /* Get the map. */ 860eaa5176SVarad Gautam status = efi_bs_call(get_memory_map, &map_size, 871ae9072eSZixuan Wang m, &key, &desc_size, &desc_ver); 880eaa5176SVarad Gautam if (status != EFI_SUCCESS) { 890eaa5176SVarad Gautam efi_free_pool(m); 900eaa5176SVarad Gautam goto out; 910eaa5176SVarad Gautam } 920eaa5176SVarad Gautam 931ae9072eSZixuan Wang *map->desc_ver = desc_ver; 940eaa5176SVarad Gautam *map->desc_size = desc_size; 950eaa5176SVarad Gautam *map->map_size = map_size; 960eaa5176SVarad Gautam *map->key_ptr = key; 970eaa5176SVarad Gautam out: 980eaa5176SVarad Gautam *map->map = m; 990eaa5176SVarad Gautam return status; 1000eaa5176SVarad Gautam } 1010eaa5176SVarad Gautam 102b4e8c300SZixuan Wang efi_status_t efi_exit_boot_services(void *handle, struct efi_boot_memmap *map) 1030eaa5176SVarad Gautam { 104b4e8c300SZixuan Wang return efi_bs_call(exit_boot_services, handle, *map->key_ptr); 1050eaa5176SVarad Gautam } 1060eaa5176SVarad Gautam 107f20589d6SZixuan Wang efi_status_t efi_get_system_config_table(efi_guid_t table_guid, void **table) 108f20589d6SZixuan Wang { 109f20589d6SZixuan Wang size_t i; 110f20589d6SZixuan Wang efi_config_table_t *tables; 111f20589d6SZixuan Wang 112f20589d6SZixuan Wang tables = (efi_config_table_t *)efi_system_table->tables; 113f20589d6SZixuan Wang for (i = 0; i < efi_system_table->nr_tables; i++) { 114f20589d6SZixuan Wang if (!memcmp(&table_guid, &tables[i].guid, sizeof(efi_guid_t))) { 115f20589d6SZixuan Wang *table = tables[i].table; 116f20589d6SZixuan Wang return EFI_SUCCESS; 117f20589d6SZixuan Wang } 118f20589d6SZixuan Wang } 119f20589d6SZixuan Wang return EFI_NOT_FOUND; 120f20589d6SZixuan Wang } 121f20589d6SZixuan Wang 1222f47d025SZixuan Wang static void efi_exit(efi_status_t code) 1232f47d025SZixuan Wang { 1242f47d025SZixuan Wang exit(code); 1252f47d025SZixuan Wang 1262f47d025SZixuan Wang /* 1272f47d025SZixuan Wang * Fallback to UEFI reset_system() service, in case testdev is 1282f47d025SZixuan Wang * missing and exit() does not properly exit. 1292f47d025SZixuan Wang */ 1302f47d025SZixuan Wang efi_rs_call(reset_system, EFI_RESET_SHUTDOWN, code, 0, NULL); 1312f47d025SZixuan Wang } 1322f47d025SZixuan Wang 13385c3c524SNikos Nikoleris /* Adapted from drivers/firmware/efi/libstub/efi-stub.c */ 13485c3c524SNikos Nikoleris static char *efi_convert_cmdline(struct efi_loaded_image_64 *image, int *cmd_line_len) 13585c3c524SNikos Nikoleris { 13685c3c524SNikos Nikoleris const u16 *s2; 13785c3c524SNikos Nikoleris unsigned long cmdline_addr = 0; 13885c3c524SNikos Nikoleris int options_chars = image->load_options_size; 13985c3c524SNikos Nikoleris const u16 *options = image->load_options; 14085c3c524SNikos Nikoleris int options_bytes = 0, safe_options_bytes = 0; /* UTF-8 bytes */ 14185c3c524SNikos Nikoleris bool in_quote = false; 14285c3c524SNikos Nikoleris efi_status_t status; 14385c3c524SNikos Nikoleris const int COMMAND_LINE_SIZE = 2048; 14485c3c524SNikos Nikoleris 14585c3c524SNikos Nikoleris if (options) { 14685c3c524SNikos Nikoleris s2 = options; 14785c3c524SNikos Nikoleris while (options_bytes < COMMAND_LINE_SIZE && options_chars--) { 14885c3c524SNikos Nikoleris u16 c = *s2++; 14985c3c524SNikos Nikoleris 15085c3c524SNikos Nikoleris if (c < 0x80) { 15185c3c524SNikos Nikoleris if (c == L'\0' || c == L'\n') 15285c3c524SNikos Nikoleris break; 15385c3c524SNikos Nikoleris if (c == L'"') 15485c3c524SNikos Nikoleris in_quote = !in_quote; 15585c3c524SNikos Nikoleris else if (!in_quote && isspace((char)c)) 15685c3c524SNikos Nikoleris safe_options_bytes = options_bytes; 15785c3c524SNikos Nikoleris 15885c3c524SNikos Nikoleris options_bytes++; 15985c3c524SNikos Nikoleris continue; 16085c3c524SNikos Nikoleris } 16185c3c524SNikos Nikoleris 16285c3c524SNikos Nikoleris /* 16385c3c524SNikos Nikoleris * Get the number of UTF-8 bytes corresponding to a 16485c3c524SNikos Nikoleris * UTF-16 character. 16585c3c524SNikos Nikoleris * The first part handles everything in the BMP. 16685c3c524SNikos Nikoleris */ 16785c3c524SNikos Nikoleris options_bytes += 2 + (c >= 0x800); 16885c3c524SNikos Nikoleris /* 16985c3c524SNikos Nikoleris * Add one more byte for valid surrogate pairs. Invalid 17085c3c524SNikos Nikoleris * surrogates will be replaced with 0xfffd and take up 17185c3c524SNikos Nikoleris * only 3 bytes. 17285c3c524SNikos Nikoleris */ 17385c3c524SNikos Nikoleris if ((c & 0xfc00) == 0xd800) { 17485c3c524SNikos Nikoleris /* 17585c3c524SNikos Nikoleris * If the very last word is a high surrogate, 17685c3c524SNikos Nikoleris * we must ignore it since we can't access the 17785c3c524SNikos Nikoleris * low surrogate. 17885c3c524SNikos Nikoleris */ 17985c3c524SNikos Nikoleris if (!options_chars) { 18085c3c524SNikos Nikoleris options_bytes -= 3; 18185c3c524SNikos Nikoleris } else if ((*s2 & 0xfc00) == 0xdc00) { 18285c3c524SNikos Nikoleris options_bytes++; 18385c3c524SNikos Nikoleris options_chars--; 18485c3c524SNikos Nikoleris s2++; 18585c3c524SNikos Nikoleris } 18685c3c524SNikos Nikoleris } 18785c3c524SNikos Nikoleris } 18885c3c524SNikos Nikoleris if (options_bytes >= COMMAND_LINE_SIZE) { 18985c3c524SNikos Nikoleris options_bytes = safe_options_bytes; 19085c3c524SNikos Nikoleris printf("Command line is too long: truncated to %d bytes\n", 19185c3c524SNikos Nikoleris options_bytes); 19285c3c524SNikos Nikoleris } 19385c3c524SNikos Nikoleris } 19485c3c524SNikos Nikoleris 19585c3c524SNikos Nikoleris options_bytes++; /* NUL termination */ 19685c3c524SNikos Nikoleris 19785c3c524SNikos Nikoleris status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, options_bytes, (void **)&cmdline_addr); 19885c3c524SNikos Nikoleris if (status != EFI_SUCCESS) 19985c3c524SNikos Nikoleris return NULL; 20085c3c524SNikos Nikoleris 20185c3c524SNikos Nikoleris snprintf((char *)cmdline_addr, options_bytes, "%.*ls", options_bytes - 1, options); 20285c3c524SNikos Nikoleris 20385c3c524SNikos Nikoleris *cmd_line_len = options_bytes; 20485c3c524SNikos Nikoleris return (char *)cmdline_addr; 20585c3c524SNikos Nikoleris } 20685c3c524SNikos Nikoleris 207bb294dfdSPavan Kumar Paluri #if defined(__aarch64__) || defined(__riscv) 208529ab889SNikos Nikoleris /* 209529ab889SNikos Nikoleris * Open the file and read it into a buffer. 210529ab889SNikos Nikoleris */ 211529ab889SNikos Nikoleris static void efi_load_image(efi_handle_t handle, struct efi_loaded_image_64 *image, void **data, 212529ab889SNikos Nikoleris int *datasize, efi_char16_t *path_name) 213529ab889SNikos Nikoleris { 214529ab889SNikos Nikoleris uint64_t buffer_size = sizeof(efi_file_info_t); 215529ab889SNikos Nikoleris efi_file_info_t *file_info; 216529ab889SNikos Nikoleris efi_file_io_interface_t *io_if; 217529ab889SNikos Nikoleris efi_file_t *root, *file; 218529ab889SNikos Nikoleris efi_status_t status; 219529ab889SNikos Nikoleris efi_guid_t file_system_proto_guid = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID; 220529ab889SNikos Nikoleris efi_guid_t file_info_guid = EFI_FILE_INFO_ID; 221529ab889SNikos Nikoleris 222529ab889SNikos Nikoleris /* Open the device */ 223529ab889SNikos Nikoleris status = efi_bs_call(handle_protocol, image->device_handle, &file_system_proto_guid, 224529ab889SNikos Nikoleris (void **)&io_if); 225529ab889SNikos Nikoleris if (status != EFI_SUCCESS) 226529ab889SNikos Nikoleris return; 227529ab889SNikos Nikoleris 228529ab889SNikos Nikoleris status = io_if->open_volume(io_if, &root); 229529ab889SNikos Nikoleris if (status != EFI_SUCCESS) 230529ab889SNikos Nikoleris return; 231529ab889SNikos Nikoleris 232529ab889SNikos Nikoleris /* And then open the file */ 233529ab889SNikos Nikoleris status = root->open(root, &file, path_name, EFI_FILE_MODE_READ, 0); 234529ab889SNikos Nikoleris if (status != EFI_SUCCESS) { 235529ab889SNikos Nikoleris printf("Failed to open %ls - %lx\n", path_name, status); 236529ab889SNikos Nikoleris assert(status == EFI_SUCCESS); 237529ab889SNikos Nikoleris } 238529ab889SNikos Nikoleris 239529ab889SNikos Nikoleris /* Find the file size in order to allocate the buffer */ 240529ab889SNikos Nikoleris status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, buffer_size, (void **)&file_info); 241529ab889SNikos Nikoleris if (status != EFI_SUCCESS) 242529ab889SNikos Nikoleris return; 243529ab889SNikos Nikoleris 244529ab889SNikos Nikoleris status = file->get_info(file, &file_info_guid, &buffer_size, file_info); 245529ab889SNikos Nikoleris if (status == EFI_BUFFER_TOO_SMALL) { 246529ab889SNikos Nikoleris efi_free_pool(file_info); 247529ab889SNikos Nikoleris status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, buffer_size, (void **)&file_info); 248529ab889SNikos Nikoleris assert(file_info); 249529ab889SNikos Nikoleris status = file->get_info(file, &file_info_guid, &buffer_size, file_info); 250529ab889SNikos Nikoleris } 251529ab889SNikos Nikoleris assert(status == EFI_SUCCESS); 252529ab889SNikos Nikoleris 253529ab889SNikos Nikoleris buffer_size = file_info->file_size; 254529ab889SNikos Nikoleris 255529ab889SNikos Nikoleris efi_free_pool(file_info); 256529ab889SNikos Nikoleris 257529ab889SNikos Nikoleris status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, buffer_size, (void **)data); 258529ab889SNikos Nikoleris assert(*data); 259529ab889SNikos Nikoleris /* Perform the actual read */ 260529ab889SNikos Nikoleris status = file->read(file, &buffer_size, *data); 261529ab889SNikos Nikoleris if (status == EFI_BUFFER_TOO_SMALL) { 262529ab889SNikos Nikoleris efi_free_pool(*data); 263529ab889SNikos Nikoleris status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, buffer_size, (void **)data); 264529ab889SNikos Nikoleris status = file->read(file, &buffer_size, *data); 265529ab889SNikos Nikoleris } 266529ab889SNikos Nikoleris assert(status == EFI_SUCCESS); 267529ab889SNikos Nikoleris 268529ab889SNikos Nikoleris *datasize = buffer_size; 269529ab889SNikos Nikoleris } 270529ab889SNikos Nikoleris 271529ab889SNikos Nikoleris static int efi_grow_buffer(efi_status_t *status, void **buffer, uint64_t buffer_size) 272529ab889SNikos Nikoleris { 273529ab889SNikos Nikoleris int try_again; 274529ab889SNikos Nikoleris 275529ab889SNikos Nikoleris if (!*buffer && buffer_size) { 276529ab889SNikos Nikoleris *status = EFI_BUFFER_TOO_SMALL; 277529ab889SNikos Nikoleris } 278529ab889SNikos Nikoleris 279529ab889SNikos Nikoleris try_again = 0; 280529ab889SNikos Nikoleris if (*status == EFI_BUFFER_TOO_SMALL) { 281529ab889SNikos Nikoleris if (*buffer) 282529ab889SNikos Nikoleris efi_free_pool(*buffer); 283529ab889SNikos Nikoleris 284529ab889SNikos Nikoleris efi_bs_call(allocate_pool, EFI_LOADER_DATA, buffer_size, buffer); 285529ab889SNikos Nikoleris if (*buffer) { 286529ab889SNikos Nikoleris try_again = 1; 287529ab889SNikos Nikoleris } else { 288529ab889SNikos Nikoleris *status = EFI_OUT_OF_RESOURCES; 289529ab889SNikos Nikoleris } 290529ab889SNikos Nikoleris } 291529ab889SNikos Nikoleris 292529ab889SNikos Nikoleris if (!try_again && EFI_ERROR(*status) && *buffer) { 293529ab889SNikos Nikoleris efi_free_pool(*buffer); 294529ab889SNikos Nikoleris *buffer = NULL; 295529ab889SNikos Nikoleris } 296529ab889SNikos Nikoleris 297529ab889SNikos Nikoleris return try_again; 298529ab889SNikos Nikoleris } 299529ab889SNikos Nikoleris 300529ab889SNikos Nikoleris static void* efi_get_var(efi_handle_t handle, struct efi_loaded_image_64 *image, efi_char16_t *var) 301529ab889SNikos Nikoleris { 302529ab889SNikos Nikoleris efi_status_t status = EFI_SUCCESS; 303529ab889SNikos Nikoleris void *val = NULL; 304529ab889SNikos Nikoleris uint64_t val_size = 100; 305529ab889SNikos Nikoleris efi_guid_t efi_var_guid = EFI_VAR_GUID; 306529ab889SNikos Nikoleris 307529ab889SNikos Nikoleris while (efi_grow_buffer(&status, &val, val_size + sizeof(efi_char16_t))) 308529ab889SNikos Nikoleris status = efi_rs_call(get_variable, var, &efi_var_guid, NULL, &val_size, val); 309529ab889SNikos Nikoleris 310529ab889SNikos Nikoleris if (val) 311529ab889SNikos Nikoleris ((efi_char16_t *)val)[val_size / sizeof(efi_char16_t)] = L'\0'; 312529ab889SNikos Nikoleris 313529ab889SNikos Nikoleris return val; 314529ab889SNikos Nikoleris } 315529ab889SNikos Nikoleris 316529ab889SNikos Nikoleris static void *efi_get_fdt(efi_handle_t handle, struct efi_loaded_image_64 *image) 317529ab889SNikos Nikoleris { 318529ab889SNikos Nikoleris efi_char16_t var[] = ENV_VARNAME_DTBFILE; 319529ab889SNikos Nikoleris efi_char16_t *val; 320529ab889SNikos Nikoleris void *fdt = NULL; 3219632ce44SAndrew Jones int fdtsize = 0; 322529ab889SNikos Nikoleris 323529ab889SNikos Nikoleris val = efi_get_var(handle, image, var); 3249632ce44SAndrew Jones if (val) { 325529ab889SNikos Nikoleris efi_load_image(handle, image, &fdt, &fdtsize, val); 3269632ce44SAndrew Jones if (fdtsize == 0) 3279632ce44SAndrew Jones return NULL; 3289632ce44SAndrew Jones } else if (efi_get_system_config_table(DEVICE_TREE_GUID, &fdt) != EFI_SUCCESS) { 3299632ce44SAndrew Jones return NULL; 3309632ce44SAndrew Jones } 331529ab889SNikos Nikoleris 3329632ce44SAndrew Jones return fdt_check_header(fdt) == 0 ? fdt : NULL; 333529ab889SNikos Nikoleris } 334bb294dfdSPavan Kumar Paluri #else 335bb294dfdSPavan Kumar Paluri static void *efi_get_fdt(efi_handle_t handle, struct efi_loaded_image_64 *image) 336bb294dfdSPavan Kumar Paluri { 337bb294dfdSPavan Kumar Paluri return NULL; 338bb294dfdSPavan Kumar Paluri } 339bb294dfdSPavan Kumar Paluri #endif 340529ab889SNikos Nikoleris 341b9f8ff7cSAndrew Jones static const struct { 342b9f8ff7cSAndrew Jones struct efi_vendor_dev_path vendor; 343b9f8ff7cSAndrew Jones struct efi_generic_dev_path end; 344b9f8ff7cSAndrew Jones } __packed initrd_dev_path = { 345b9f8ff7cSAndrew Jones { 346b9f8ff7cSAndrew Jones { 347b9f8ff7cSAndrew Jones EFI_DEV_MEDIA, 348b9f8ff7cSAndrew Jones EFI_DEV_MEDIA_VENDOR, 349b9f8ff7cSAndrew Jones sizeof(struct efi_vendor_dev_path), 350b9f8ff7cSAndrew Jones }, 351b9f8ff7cSAndrew Jones LINUX_EFI_INITRD_MEDIA_GUID 352b9f8ff7cSAndrew Jones }, { 353b9f8ff7cSAndrew Jones EFI_DEV_END_PATH, 354b9f8ff7cSAndrew Jones EFI_DEV_END_ENTIRE, 355b9f8ff7cSAndrew Jones sizeof(struct efi_generic_dev_path) 356b9f8ff7cSAndrew Jones } 357b9f8ff7cSAndrew Jones }; 358b9f8ff7cSAndrew Jones 359b9f8ff7cSAndrew Jones static void efi_load_initrd(void) 360b9f8ff7cSAndrew Jones { 361b9f8ff7cSAndrew Jones efi_guid_t lf2_proto_guid = EFI_LOAD_FILE2_PROTOCOL_GUID; 362b9f8ff7cSAndrew Jones efi_device_path_protocol_t *dp; 363b9f8ff7cSAndrew Jones efi_load_file2_protocol_t *lf2; 364b9f8ff7cSAndrew Jones efi_handle_t handle; 365b9f8ff7cSAndrew Jones efi_status_t status; 366b9f8ff7cSAndrew Jones unsigned long file_size = 0; 367b9f8ff7cSAndrew Jones 368b9f8ff7cSAndrew Jones initrd = NULL; 369b9f8ff7cSAndrew Jones initrd_size = 0; 370b9f8ff7cSAndrew Jones 371b9f8ff7cSAndrew Jones dp = (efi_device_path_protocol_t *)&initrd_dev_path; 372b9f8ff7cSAndrew Jones status = efi_bs_call(locate_device_path, &lf2_proto_guid, &dp, &handle); 373b9f8ff7cSAndrew Jones if (status != EFI_SUCCESS) 374b9f8ff7cSAndrew Jones return; 375b9f8ff7cSAndrew Jones 376b9f8ff7cSAndrew Jones status = efi_bs_call(handle_protocol, handle, &lf2_proto_guid, (void **)&lf2); 377b9f8ff7cSAndrew Jones assert(status == EFI_SUCCESS); 378b9f8ff7cSAndrew Jones 379b9f8ff7cSAndrew Jones status = efi_call_proto(lf2, load_file, dp, false, &file_size, NULL); 380b9f8ff7cSAndrew Jones assert(status == EFI_BUFFER_TOO_SMALL); 381b9f8ff7cSAndrew Jones 382b9f8ff7cSAndrew Jones status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, file_size, (void **)&initrd); 383b9f8ff7cSAndrew Jones assert(status == EFI_SUCCESS); 384b9f8ff7cSAndrew Jones 385b9f8ff7cSAndrew Jones status = efi_call_proto(lf2, load_file, dp, false, &file_size, (void *)initrd); 386b9f8ff7cSAndrew Jones assert(status == EFI_SUCCESS); 387b9f8ff7cSAndrew Jones 388b9f8ff7cSAndrew Jones initrd_size = (u32)file_size; 389b9f8ff7cSAndrew Jones 390b9f8ff7cSAndrew Jones /* 391b9f8ff7cSAndrew Jones * UEFI appends initrd=initrd to the command line when an initrd is present. 392b9f8ff7cSAndrew Jones * Remove it in order to avoid confusing unit tests. 393b9f8ff7cSAndrew Jones */ 394b9f8ff7cSAndrew Jones if (!strcmp(__argv[__argc - 1], "initrd=initrd")) { 395b9f8ff7cSAndrew Jones __argv[__argc - 1] = NULL; 396b9f8ff7cSAndrew Jones __argc -= 1; 397b9f8ff7cSAndrew Jones } 398b9f8ff7cSAndrew Jones } 399b9f8ff7cSAndrew Jones 400ad5fb883SZixuan Wang efi_status_t efi_main(efi_handle_t handle, efi_system_table_t *sys_tab) 4010eaa5176SVarad Gautam { 402ad5fb883SZixuan Wang int ret; 4031ae9072eSZixuan Wang efi_status_t status; 4041ae9072eSZixuan Wang efi_bootinfo_t efi_bootinfo; 405ad5fb883SZixuan Wang 4060eaa5176SVarad Gautam efi_system_table = sys_tab; 4070eaa5176SVarad Gautam 408b4e8c300SZixuan Wang /* Memory map struct values */ 409*b365a5b0SPavan Kumar Paluri efi_memory_desc_t *map; 410*b365a5b0SPavan Kumar Paluri unsigned long map_size, desc_size, key, buff_size; 411b4e8c300SZixuan Wang u32 desc_ver; 412b4e8c300SZixuan Wang 41385c3c524SNikos Nikoleris /* Helper variables needed to get the cmdline */ 41485c3c524SNikos Nikoleris struct efi_loaded_image_64 *image; 41585c3c524SNikos Nikoleris efi_guid_t loaded_image_proto = LOADED_IMAGE_PROTOCOL_GUID; 41685c3c524SNikos Nikoleris char *cmdline_ptr = NULL; 41785c3c524SNikos Nikoleris int cmdline_size = 0; 41885c3c524SNikos Nikoleris 41985c3c524SNikos Nikoleris /* 42085c3c524SNikos Nikoleris * Get a handle to the loaded image protocol. This is used to get 42185c3c524SNikos Nikoleris * information about the running image, such as size and the command 42285c3c524SNikos Nikoleris * line. 42385c3c524SNikos Nikoleris */ 42485c3c524SNikos Nikoleris status = efi_bs_call(handle_protocol, handle, &loaded_image_proto, (void *)&image); 42585c3c524SNikos Nikoleris if (status != EFI_SUCCESS) { 42685c3c524SNikos Nikoleris printf("Failed to get loaded image protocol\n"); 42785c3c524SNikos Nikoleris goto efi_main_error; 42885c3c524SNikos Nikoleris } 42985c3c524SNikos Nikoleris 43085c3c524SNikos Nikoleris cmdline_ptr = efi_convert_cmdline(image, &cmdline_size); 43185c3c524SNikos Nikoleris if (!cmdline_ptr) { 43285c3c524SNikos Nikoleris printf("getting command line via LOADED_IMAGE_PROTOCOL\n"); 43385c3c524SNikos Nikoleris status = EFI_OUT_OF_RESOURCES; 43485c3c524SNikos Nikoleris goto efi_main_error; 43585c3c524SNikos Nikoleris } 43685c3c524SNikos Nikoleris setup_args(cmdline_ptr); 43785c3c524SNikos Nikoleris 438b9f8ff7cSAndrew Jones efi_load_initrd(); 439b9f8ff7cSAndrew Jones 440529ab889SNikos Nikoleris efi_bootinfo.fdt = efi_get_fdt(handle, image); 441b4e8c300SZixuan Wang /* Set up efi_bootinfo */ 442b4e8c300SZixuan Wang efi_bootinfo.mem_map.map = ↦ 443b4e8c300SZixuan Wang efi_bootinfo.mem_map.map_size = &map_size; 444b4e8c300SZixuan Wang efi_bootinfo.mem_map.desc_size = &desc_size; 445b4e8c300SZixuan Wang efi_bootinfo.mem_map.desc_ver = &desc_ver; 446b4e8c300SZixuan Wang efi_bootinfo.mem_map.key_ptr = &key; 447b4e8c300SZixuan Wang efi_bootinfo.mem_map.buff_size = &buff_size; 448b4e8c300SZixuan Wang 449ba0a6fd4SAndrew Jones #ifdef __riscv 450ba0a6fd4SAndrew Jones status = efi_get_boot_hartid(); 451ba0a6fd4SAndrew Jones if (status != EFI_SUCCESS) { 452ba0a6fd4SAndrew Jones printf("Failed to get boot haritd\n"); 453ba0a6fd4SAndrew Jones goto efi_main_error; 454ba0a6fd4SAndrew Jones } 455ba0a6fd4SAndrew Jones #endif 456ba0a6fd4SAndrew Jones 457*b365a5b0SPavan Kumar Paluri status = EFI_INVALID_PARAMETER; 458*b365a5b0SPavan Kumar Paluri while (status == EFI_INVALID_PARAMETER) { 459*b365a5b0SPavan Kumar Paluri status = efi_get_memory_map(&efi_bootinfo.mem_map); 460*b365a5b0SPavan Kumar Paluri if (status != EFI_SUCCESS) { 461*b365a5b0SPavan Kumar Paluri printf("Failed to get memory map\n"); 462*b365a5b0SPavan Kumar Paluri goto efi_main_error; 463*b365a5b0SPavan Kumar Paluri } 464b4e8c300SZixuan Wang /* 465*b365a5b0SPavan Kumar Paluri * Exit EFI boot services, let kvm-unit-tests take full 466*b365a5b0SPavan Kumar Paluri * control of the guest. 467b4e8c300SZixuan Wang */ 468b4e8c300SZixuan Wang status = efi_exit_boot_services(handle, &efi_bootinfo.mem_map); 469*b365a5b0SPavan Kumar Paluri if (status == EFI_INVALID_PARAMETER) 470*b365a5b0SPavan Kumar Paluri efi_free_pool(*efi_bootinfo.mem_map.map); 471*b365a5b0SPavan Kumar Paluri } 472*b365a5b0SPavan Kumar Paluri 4731ae9072eSZixuan Wang if (status != EFI_SUCCESS) { 4741ae9072eSZixuan Wang printf("Failed to exit boot services\n"); 475b4e8c300SZixuan Wang goto efi_main_error; 4761ae9072eSZixuan Wang } 4771ae9072eSZixuan Wang 478b4e8c300SZixuan Wang /* Set up arch-specific resources */ 479b4e8c300SZixuan Wang status = setup_efi(&efi_bootinfo); 480b4e8c300SZixuan Wang if (status != EFI_SUCCESS) { 481b4e8c300SZixuan Wang printf("Failed to set up arch-specific resources\n"); 482b4e8c300SZixuan Wang goto efi_main_error; 483b4e8c300SZixuan Wang } 484b4e8c300SZixuan Wang 48525ef5154SNadav Amit printf("Address of image is: 0x%lx\n", (unsigned long)&_text); 48625ef5154SNadav Amit 487b4e8c300SZixuan Wang /* Run the test case */ 488ad5fb883SZixuan Wang ret = main(__argc, __argv, __environ); 489ad5fb883SZixuan Wang 4902f47d025SZixuan Wang /* Shutdown the guest VM */ 4912f47d025SZixuan Wang efi_exit(ret); 492ad5fb883SZixuan Wang 493ad5fb883SZixuan Wang /* Unreachable */ 494ad5fb883SZixuan Wang return EFI_UNSUPPORTED; 495b4e8c300SZixuan Wang 496b4e8c300SZixuan Wang efi_main_error: 497b4e8c300SZixuan Wang /* Shutdown the guest with error EFI status */ 4982f47d025SZixuan Wang efi_exit(status); 499b4e8c300SZixuan Wang 500b4e8c300SZixuan Wang /* Unreachable */ 501b4e8c300SZixuan Wang return EFI_UNSUPPORTED; 5020eaa5176SVarad Gautam } 503