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