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 #include <libcflat.h> 10 #include <argv.h> 11 #include <ctype.h> 12 #include <stdlib.h> 13 #include <asm/setup.h> 14 #include "efi.h" 15 16 /* From each arch */ 17 extern char *initrd; 18 extern u32 initrd_size; 19 20 /* From lib/argv.c */ 21 extern int __argc, __envc; 22 extern char *__argv[100]; 23 extern char *__environ[200]; 24 25 extern char _text; 26 27 extern int main(int argc, char **argv, char **envp); 28 29 efi_system_table_t *efi_system_table = NULL; 30 31 #ifdef __riscv 32 #define RISCV_EFI_BOOT_PROTOCOL_GUID EFI_GUID(0xccd15fec, 0x6f73, 0x4eec, 0x83, 0x95, 0x3e, 0x69, 0xe4, 0xb9, 0x40, 0xbf) 33 34 unsigned long boot_hartid; 35 36 struct riscv_efi_boot_protocol { 37 u64 revision; 38 efi_status_t (*get_boot_hartid)(struct riscv_efi_boot_protocol *, 39 unsigned long *boot_hartid); 40 }; 41 42 static efi_status_t efi_get_boot_hartid(void) 43 { 44 efi_guid_t boot_protocol_guid = RISCV_EFI_BOOT_PROTOCOL_GUID; 45 struct riscv_efi_boot_protocol *boot_protocol; 46 efi_status_t status; 47 48 status = efi_bs_call(locate_protocol, &boot_protocol_guid, NULL, 49 (void **)&boot_protocol); 50 if (status != EFI_SUCCESS) 51 return status; 52 return efi_call_proto(boot_protocol, get_boot_hartid, &boot_hartid); 53 } 54 #endif 55 56 static void efi_free_pool(void *ptr) 57 { 58 efi_bs_call(free_pool, ptr); 59 } 60 61 efi_status_t efi_get_memory_map(struct efi_boot_memmap *map) 62 { 63 efi_memory_desc_t *m = NULL; 64 efi_status_t status; 65 unsigned long key = 0, map_size = 0, desc_size = 0; 66 u32 desc_ver; 67 68 status = efi_bs_call(get_memory_map, &map_size, 69 NULL, &key, &desc_size, &desc_ver); 70 if (status != EFI_BUFFER_TOO_SMALL || map_size == 0) 71 goto out; 72 73 /* 74 * Pad map_size with additional descriptors so we don't need to 75 * retry. 76 */ 77 map_size += 4 * desc_size; 78 *map->buff_size = map_size; 79 status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, 80 map_size, (void **)&m); 81 if (status != EFI_SUCCESS) 82 goto out; 83 84 /* Get the map. */ 85 status = efi_bs_call(get_memory_map, &map_size, 86 m, &key, &desc_size, &desc_ver); 87 if (status != EFI_SUCCESS) { 88 efi_free_pool(m); 89 goto out; 90 } 91 92 *map->desc_ver = desc_ver; 93 *map->desc_size = desc_size; 94 *map->map_size = map_size; 95 *map->key_ptr = key; 96 out: 97 *map->map = m; 98 return status; 99 } 100 101 efi_status_t efi_exit_boot_services(void *handle, struct efi_boot_memmap *map) 102 { 103 return efi_bs_call(exit_boot_services, handle, *map->key_ptr); 104 } 105 106 efi_status_t efi_get_system_config_table(efi_guid_t table_guid, void **table) 107 { 108 size_t i; 109 efi_config_table_t *tables; 110 111 tables = (efi_config_table_t *)efi_system_table->tables; 112 for (i = 0; i < efi_system_table->nr_tables; i++) { 113 if (!memcmp(&table_guid, &tables[i].guid, sizeof(efi_guid_t))) { 114 *table = tables[i].table; 115 return EFI_SUCCESS; 116 } 117 } 118 return EFI_NOT_FOUND; 119 } 120 121 static void efi_exit(efi_status_t code) 122 { 123 exit(code); 124 125 /* 126 * Fallback to UEFI reset_system() service, in case testdev is 127 * missing and exit() does not properly exit. 128 */ 129 efi_rs_call(reset_system, EFI_RESET_SHUTDOWN, code, 0, NULL); 130 } 131 132 /* Adapted from drivers/firmware/efi/libstub/efi-stub.c */ 133 static char *efi_convert_cmdline(struct efi_loaded_image_64 *image, int *cmd_line_len) 134 { 135 const u16 *s2; 136 unsigned long cmdline_addr = 0; 137 int options_chars = image->load_options_size; 138 const u16 *options = image->load_options; 139 int options_bytes = 0, safe_options_bytes = 0; /* UTF-8 bytes */ 140 bool in_quote = false; 141 efi_status_t status; 142 const int COMMAND_LINE_SIZE = 2048; 143 144 if (options) { 145 s2 = options; 146 while (options_bytes < COMMAND_LINE_SIZE && options_chars--) { 147 u16 c = *s2++; 148 149 if (c < 0x80) { 150 if (c == L'\0' || c == L'\n') 151 break; 152 if (c == L'"') 153 in_quote = !in_quote; 154 else if (!in_quote && isspace((char)c)) 155 safe_options_bytes = options_bytes; 156 157 options_bytes++; 158 continue; 159 } 160 161 /* 162 * Get the number of UTF-8 bytes corresponding to a 163 * UTF-16 character. 164 * The first part handles everything in the BMP. 165 */ 166 options_bytes += 2 + (c >= 0x800); 167 /* 168 * Add one more byte for valid surrogate pairs. Invalid 169 * surrogates will be replaced with 0xfffd and take up 170 * only 3 bytes. 171 */ 172 if ((c & 0xfc00) == 0xd800) { 173 /* 174 * If the very last word is a high surrogate, 175 * we must ignore it since we can't access the 176 * low surrogate. 177 */ 178 if (!options_chars) { 179 options_bytes -= 3; 180 } else if ((*s2 & 0xfc00) == 0xdc00) { 181 options_bytes++; 182 options_chars--; 183 s2++; 184 } 185 } 186 } 187 if (options_bytes >= COMMAND_LINE_SIZE) { 188 options_bytes = safe_options_bytes; 189 printf("Command line is too long: truncated to %d bytes\n", 190 options_bytes); 191 } 192 } 193 194 options_bytes++; /* NUL termination */ 195 196 status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, options_bytes, (void **)&cmdline_addr); 197 if (status != EFI_SUCCESS) 198 return NULL; 199 200 snprintf((char *)cmdline_addr, options_bytes, "%.*ls", options_bytes - 1, options); 201 202 *cmd_line_len = options_bytes; 203 return (char *)cmdline_addr; 204 } 205 206 #if defined(__aarch64__) || defined(__riscv) 207 #include "libfdt/libfdt.h" 208 /* 209 * Open the file and read it into a buffer. 210 */ 211 static void efi_load_image(efi_handle_t handle, struct efi_loaded_image_64 *image, void **data, 212 int *datasize, efi_char16_t *path_name) 213 { 214 uint64_t buffer_size = sizeof(efi_file_info_t); 215 efi_file_info_t *file_info; 216 efi_file_io_interface_t *io_if; 217 efi_file_t *root, *file; 218 efi_status_t status; 219 efi_guid_t file_system_proto_guid = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID; 220 efi_guid_t file_info_guid = EFI_FILE_INFO_ID; 221 222 /* Open the device */ 223 status = efi_bs_call(handle_protocol, image->device_handle, &file_system_proto_guid, 224 (void **)&io_if); 225 if (status != EFI_SUCCESS) 226 return; 227 228 status = io_if->open_volume(io_if, &root); 229 if (status != EFI_SUCCESS) 230 return; 231 232 /* And then open the file */ 233 status = root->open(root, &file, path_name, EFI_FILE_MODE_READ, 0); 234 if (status != EFI_SUCCESS) { 235 printf("Failed to open %ls - %lx\n", path_name, status); 236 assert(status == EFI_SUCCESS); 237 } 238 239 /* Find the file size in order to allocate the buffer */ 240 status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, buffer_size, (void **)&file_info); 241 if (status != EFI_SUCCESS) 242 return; 243 244 status = file->get_info(file, &file_info_guid, &buffer_size, file_info); 245 if (status == EFI_BUFFER_TOO_SMALL) { 246 efi_free_pool(file_info); 247 status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, buffer_size, (void **)&file_info); 248 assert(file_info); 249 status = file->get_info(file, &file_info_guid, &buffer_size, file_info); 250 } 251 assert(status == EFI_SUCCESS); 252 253 buffer_size = file_info->file_size; 254 255 efi_free_pool(file_info); 256 257 status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, buffer_size, (void **)data); 258 assert(*data); 259 /* Perform the actual read */ 260 status = file->read(file, &buffer_size, *data); 261 if (status == EFI_BUFFER_TOO_SMALL) { 262 efi_free_pool(*data); 263 status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, buffer_size, (void **)data); 264 status = file->read(file, &buffer_size, *data); 265 } 266 assert(status == EFI_SUCCESS); 267 268 *datasize = buffer_size; 269 } 270 271 static int efi_grow_buffer(efi_status_t *status, void **buffer, uint64_t buffer_size) 272 { 273 int try_again; 274 275 if (!*buffer && buffer_size) { 276 *status = EFI_BUFFER_TOO_SMALL; 277 } 278 279 try_again = 0; 280 if (*status == EFI_BUFFER_TOO_SMALL) { 281 if (*buffer) 282 efi_free_pool(*buffer); 283 284 efi_bs_call(allocate_pool, EFI_LOADER_DATA, buffer_size, buffer); 285 if (*buffer) { 286 try_again = 1; 287 } else { 288 *status = EFI_OUT_OF_RESOURCES; 289 } 290 } 291 292 if (!try_again && EFI_ERROR(*status) && *buffer) { 293 efi_free_pool(*buffer); 294 *buffer = NULL; 295 } 296 297 return try_again; 298 } 299 300 static void* efi_get_var(efi_handle_t handle, struct efi_loaded_image_64 *image, efi_char16_t *var) 301 { 302 efi_status_t status = EFI_SUCCESS; 303 void *val = NULL; 304 uint64_t val_size = 100; 305 efi_guid_t efi_var_guid = EFI_VAR_GUID; 306 307 while (efi_grow_buffer(&status, &val, val_size + sizeof(efi_char16_t))) 308 status = efi_rs_call(get_variable, var, &efi_var_guid, NULL, &val_size, val); 309 310 if (val) 311 ((efi_char16_t *)val)[val_size / sizeof(efi_char16_t)] = L'\0'; 312 313 return val; 314 } 315 316 static void *efi_get_fdt(efi_handle_t handle, struct efi_loaded_image_64 *image) 317 { 318 efi_char16_t var[] = ENV_VARNAME_DTBFILE; 319 efi_char16_t *val; 320 void *fdt = NULL; 321 int fdtsize = 0; 322 323 val = efi_get_var(handle, image, var); 324 if (val) { 325 efi_load_image(handle, image, &fdt, &fdtsize, val); 326 if (fdtsize == 0) 327 return NULL; 328 } else if (efi_get_system_config_table(DEVICE_TREE_GUID, &fdt) != EFI_SUCCESS) { 329 return NULL; 330 } 331 332 return fdt_check_header(fdt) == 0 ? fdt : NULL; 333 } 334 #else 335 static void *efi_get_fdt(efi_handle_t handle, struct efi_loaded_image_64 *image) 336 { 337 return NULL; 338 } 339 #endif 340 341 static const struct { 342 struct efi_vendor_dev_path vendor; 343 struct efi_generic_dev_path end; 344 } __packed initrd_dev_path = { 345 { 346 { 347 EFI_DEV_MEDIA, 348 EFI_DEV_MEDIA_VENDOR, 349 sizeof(struct efi_vendor_dev_path), 350 }, 351 LINUX_EFI_INITRD_MEDIA_GUID 352 }, { 353 EFI_DEV_END_PATH, 354 EFI_DEV_END_ENTIRE, 355 sizeof(struct efi_generic_dev_path) 356 } 357 }; 358 359 static void efi_load_initrd(void) 360 { 361 efi_guid_t lf2_proto_guid = EFI_LOAD_FILE2_PROTOCOL_GUID; 362 efi_device_path_protocol_t *dp; 363 efi_load_file2_protocol_t *lf2; 364 efi_handle_t handle; 365 efi_status_t status; 366 unsigned long file_size = 0; 367 368 initrd = NULL; 369 initrd_size = 0; 370 371 dp = (efi_device_path_protocol_t *)&initrd_dev_path; 372 status = efi_bs_call(locate_device_path, &lf2_proto_guid, &dp, &handle); 373 if (status != EFI_SUCCESS) 374 return; 375 376 status = efi_bs_call(handle_protocol, handle, &lf2_proto_guid, (void **)&lf2); 377 assert(status == EFI_SUCCESS); 378 379 status = efi_call_proto(lf2, load_file, dp, false, &file_size, NULL); 380 assert(status == EFI_BUFFER_TOO_SMALL); 381 382 status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, file_size, (void **)&initrd); 383 assert(status == EFI_SUCCESS); 384 385 status = efi_call_proto(lf2, load_file, dp, false, &file_size, (void *)initrd); 386 assert(status == EFI_SUCCESS); 387 388 initrd_size = (u32)file_size; 389 390 /* 391 * UEFI appends initrd=initrd to the command line when an initrd is present. 392 * Remove it in order to avoid confusing unit tests. 393 */ 394 if (!strcmp(__argv[__argc - 1], "initrd=initrd")) { 395 __argv[__argc - 1] = NULL; 396 __argc -= 1; 397 } 398 } 399 400 efi_status_t efi_main(efi_handle_t handle, efi_system_table_t *sys_tab) 401 { 402 int ret; 403 efi_status_t status; 404 efi_bootinfo_t efi_bootinfo; 405 406 efi_system_table = sys_tab; 407 408 /* Memory map struct values */ 409 efi_memory_desc_t *map; 410 unsigned long map_size, desc_size, key, buff_size; 411 u32 desc_ver; 412 413 /* Helper variables needed to get the cmdline */ 414 struct efi_loaded_image_64 *image; 415 efi_guid_t loaded_image_proto = LOADED_IMAGE_PROTOCOL_GUID; 416 char *cmdline_ptr = NULL; 417 int cmdline_size = 0; 418 419 /* 420 * Get a handle to the loaded image protocol. This is used to get 421 * information about the running image, such as size and the command 422 * line. 423 */ 424 status = efi_bs_call(handle_protocol, handle, &loaded_image_proto, (void *)&image); 425 if (status != EFI_SUCCESS) { 426 printf("Failed to get loaded image protocol\n"); 427 goto efi_main_error; 428 } 429 430 cmdline_ptr = efi_convert_cmdline(image, &cmdline_size); 431 if (!cmdline_ptr) { 432 printf("getting command line via LOADED_IMAGE_PROTOCOL\n"); 433 status = EFI_OUT_OF_RESOURCES; 434 goto efi_main_error; 435 } 436 setup_args(cmdline_ptr); 437 438 efi_load_initrd(); 439 440 efi_bootinfo.fdt = efi_get_fdt(handle, image); 441 /* Set up efi_bootinfo */ 442 efi_bootinfo.mem_map.map = ↦ 443 efi_bootinfo.mem_map.map_size = &map_size; 444 efi_bootinfo.mem_map.desc_size = &desc_size; 445 efi_bootinfo.mem_map.desc_ver = &desc_ver; 446 efi_bootinfo.mem_map.key_ptr = &key; 447 efi_bootinfo.mem_map.buff_size = &buff_size; 448 449 #ifdef __riscv 450 status = efi_get_boot_hartid(); 451 if (status != EFI_SUCCESS) { 452 printf("Failed to get boot haritd\n"); 453 goto efi_main_error; 454 } 455 #endif 456 457 status = EFI_INVALID_PARAMETER; 458 while (status == EFI_INVALID_PARAMETER) { 459 status = efi_get_memory_map(&efi_bootinfo.mem_map); 460 if (status != EFI_SUCCESS) { 461 printf("Failed to get memory map\n"); 462 goto efi_main_error; 463 } 464 /* 465 * Exit EFI boot services, let kvm-unit-tests take full 466 * control of the guest. 467 */ 468 status = efi_exit_boot_services(handle, &efi_bootinfo.mem_map); 469 if (status == EFI_INVALID_PARAMETER) 470 efi_free_pool(*efi_bootinfo.mem_map.map); 471 } 472 473 if (status != EFI_SUCCESS) { 474 printf("Failed to exit boot services\n"); 475 goto efi_main_error; 476 } 477 478 /* Set up arch-specific resources */ 479 status = setup_efi(&efi_bootinfo); 480 if (status != EFI_SUCCESS) { 481 printf("Failed to set up arch-specific resources\n"); 482 goto efi_main_error; 483 } 484 485 printf("Address of image is: 0x%lx\n", (unsigned long)&_text); 486 487 /* Run the test case */ 488 ret = main(__argc, __argv, __environ); 489 490 /* Shutdown the guest VM */ 491 efi_exit(ret); 492 493 /* Unreachable */ 494 return EFI_UNSUPPORTED; 495 496 efi_main_error: 497 /* Shutdown the guest with error EFI status */ 498 efi_exit(status); 499 500 /* Unreachable */ 501 return EFI_UNSUPPORTED; 502 } 503