1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Helper functions used by the EFI stub on multiple 4 * architectures. This should be #included by the EFI stub 5 * implementation files. 6 * 7 * Copyright 2011 Intel Corporation; author Matt Fleming 8 */ 9 10 #include <linux/stdarg.h> 11 12 #include <linux/efi.h> 13 #include <linux/kernel.h> 14 #include <asm/efi.h> 15 #include <asm/setup.h> 16 17 #include "efistub.h" 18 19 bool efi_nochunk; 20 bool efi_nokaslr = !IS_ENABLED(CONFIG_RANDOMIZE_BASE); 21 bool efi_novamap; 22 23 static bool efi_noinitrd; 24 static bool efi_nosoftreserve; 25 static bool efi_disable_pci_dma = IS_ENABLED(CONFIG_EFI_DISABLE_PCI_DMA); 26 27 bool __pure __efi_soft_reserve_enabled(void) 28 { 29 return !efi_nosoftreserve; 30 } 31 32 /** 33 * efi_parse_options() - Parse EFI command line options 34 * @cmdline: kernel command line 35 * 36 * Parse the ASCII string @cmdline for EFI options, denoted by the efi= 37 * option, e.g. efi=nochunk. 38 * 39 * It should be noted that efi= is parsed in two very different 40 * environments, first in the early boot environment of the EFI boot 41 * stub, and subsequently during the kernel boot. 42 * 43 * Return: status code 44 */ 45 efi_status_t efi_parse_options(char const *cmdline) 46 { 47 size_t len; 48 efi_status_t status; 49 char *str, *buf; 50 51 if (!cmdline) 52 return EFI_SUCCESS; 53 54 len = strnlen(cmdline, COMMAND_LINE_SIZE - 1) + 1; 55 status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, len, (void **)&buf); 56 if (status != EFI_SUCCESS) 57 return status; 58 59 memcpy(buf, cmdline, len - 1); 60 buf[len - 1] = '\0'; 61 str = skip_spaces(buf); 62 63 while (*str) { 64 char *param, *val; 65 66 str = next_arg(str, ¶m, &val); 67 if (!val && !strcmp(param, "--")) 68 break; 69 70 if (!strcmp(param, "nokaslr")) { 71 efi_nokaslr = true; 72 } else if (!strcmp(param, "quiet")) { 73 efi_loglevel = CONSOLE_LOGLEVEL_QUIET; 74 } else if (!strcmp(param, "noinitrd")) { 75 efi_noinitrd = true; 76 } else if (IS_ENABLED(CONFIG_X86_64) && !strcmp(param, "no5lvl")) { 77 efi_no5lvl = true; 78 } else if (!strcmp(param, "efi") && val) { 79 efi_nochunk = parse_option_str(val, "nochunk"); 80 efi_novamap |= parse_option_str(val, "novamap"); 81 82 efi_nosoftreserve = IS_ENABLED(CONFIG_EFI_SOFT_RESERVE) && 83 parse_option_str(val, "nosoftreserve"); 84 85 if (parse_option_str(val, "disable_early_pci_dma")) 86 efi_disable_pci_dma = true; 87 if (parse_option_str(val, "no_disable_early_pci_dma")) 88 efi_disable_pci_dma = false; 89 if (parse_option_str(val, "debug")) 90 efi_loglevel = CONSOLE_LOGLEVEL_DEBUG; 91 } else if (!strcmp(param, "video") && 92 val && strstarts(val, "efifb:")) { 93 efi_parse_option_graphics(val + strlen("efifb:")); 94 } 95 } 96 efi_bs_call(free_pool, buf); 97 return EFI_SUCCESS; 98 } 99 100 /* 101 * The EFI_LOAD_OPTION descriptor has the following layout: 102 * u32 Attributes; 103 * u16 FilePathListLength; 104 * u16 Description[]; 105 * efi_device_path_protocol_t FilePathList[]; 106 * u8 OptionalData[]; 107 * 108 * This function validates and unpacks the variable-size data fields. 109 */ 110 static 111 bool efi_load_option_unpack(efi_load_option_unpacked_t *dest, 112 const efi_load_option_t *src, size_t size) 113 { 114 const void *pos; 115 u16 c; 116 efi_device_path_protocol_t header; 117 const efi_char16_t *description; 118 const efi_device_path_protocol_t *file_path_list; 119 120 if (size < offsetof(efi_load_option_t, variable_data)) 121 return false; 122 pos = src->variable_data; 123 size -= offsetof(efi_load_option_t, variable_data); 124 125 if ((src->attributes & ~EFI_LOAD_OPTION_MASK) != 0) 126 return false; 127 128 /* Scan description. */ 129 description = pos; 130 do { 131 if (size < sizeof(c)) 132 return false; 133 c = *(const u16 *)pos; 134 pos += sizeof(c); 135 size -= sizeof(c); 136 } while (c != L'\0'); 137 138 /* Scan file_path_list. */ 139 file_path_list = pos; 140 do { 141 if (size < sizeof(header)) 142 return false; 143 header = *(const efi_device_path_protocol_t *)pos; 144 if (header.length < sizeof(header)) 145 return false; 146 if (size < header.length) 147 return false; 148 pos += header.length; 149 size -= header.length; 150 } while ((header.type != EFI_DEV_END_PATH && header.type != EFI_DEV_END_PATH2) || 151 (header.sub_type != EFI_DEV_END_ENTIRE)); 152 if (pos != (const void *)file_path_list + src->file_path_list_length) 153 return false; 154 155 dest->attributes = src->attributes; 156 dest->file_path_list_length = src->file_path_list_length; 157 dest->description = description; 158 dest->file_path_list = file_path_list; 159 dest->optional_data_size = size; 160 dest->optional_data = size ? pos : NULL; 161 162 return true; 163 } 164 165 /* 166 * At least some versions of Dell firmware pass the entire contents of the 167 * Boot#### variable, i.e. the EFI_LOAD_OPTION descriptor, rather than just the 168 * OptionalData field. 169 * 170 * Detect this case and extract OptionalData. 171 */ 172 void efi_apply_loadoptions_quirk(const void **load_options, u32 *load_options_size) 173 { 174 const efi_load_option_t *load_option = *load_options; 175 efi_load_option_unpacked_t load_option_unpacked; 176 177 if (!IS_ENABLED(CONFIG_X86)) 178 return; 179 if (!load_option) 180 return; 181 if (*load_options_size < sizeof(*load_option)) 182 return; 183 if ((load_option->attributes & ~EFI_LOAD_OPTION_BOOT_MASK) != 0) 184 return; 185 186 if (!efi_load_option_unpack(&load_option_unpacked, load_option, *load_options_size)) 187 return; 188 189 efi_warn_once(FW_BUG "LoadOptions is an EFI_LOAD_OPTION descriptor\n"); 190 efi_warn_once(FW_BUG "Using OptionalData as a workaround\n"); 191 192 *load_options = load_option_unpacked.optional_data; 193 *load_options_size = load_option_unpacked.optional_data_size; 194 } 195 196 enum efistub_event { 197 EFISTUB_EVT_INITRD, 198 EFISTUB_EVT_LOAD_OPTIONS, 199 EFISTUB_EVT_COUNT, 200 }; 201 202 #define STR_WITH_SIZE(s) sizeof(s), s 203 204 static const struct { 205 u32 pcr_index; 206 u32 event_id; 207 u32 event_data_len; 208 u8 event_data[52]; 209 } events[] = { 210 [EFISTUB_EVT_INITRD] = { 211 9, 212 INITRD_EVENT_TAG_ID, 213 STR_WITH_SIZE("Linux initrd") 214 }, 215 [EFISTUB_EVT_LOAD_OPTIONS] = { 216 9, 217 LOAD_OPTIONS_EVENT_TAG_ID, 218 STR_WITH_SIZE("LOADED_IMAGE::LoadOptions") 219 }, 220 }; 221 222 static efi_status_t efi_measure_tagged_event(unsigned long load_addr, 223 unsigned long load_size, 224 enum efistub_event event) 225 { 226 efi_guid_t tcg2_guid = EFI_TCG2_PROTOCOL_GUID; 227 efi_tcg2_protocol_t *tcg2 = NULL; 228 efi_status_t status; 229 230 efi_bs_call(locate_protocol, &tcg2_guid, NULL, (void **)&tcg2); 231 if (tcg2) { 232 struct efi_measured_event { 233 efi_tcg2_event_t event_data; 234 efi_tcg2_tagged_event_t tagged_event; 235 u8 tagged_event_data[]; 236 } *evt; 237 int size = sizeof(*evt) + events[event].event_data_len; 238 239 status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, size, 240 (void **)&evt); 241 if (status != EFI_SUCCESS) 242 goto fail; 243 244 evt->event_data = (struct efi_tcg2_event){ 245 .event_size = size, 246 .event_header.header_size = sizeof(evt->event_data.event_header), 247 .event_header.header_version = EFI_TCG2_EVENT_HEADER_VERSION, 248 .event_header.pcr_index = events[event].pcr_index, 249 .event_header.event_type = EV_EVENT_TAG, 250 }; 251 252 evt->tagged_event = (struct efi_tcg2_tagged_event){ 253 .tagged_event_id = events[event].event_id, 254 .tagged_event_data_size = events[event].event_data_len, 255 }; 256 257 memcpy(evt->tagged_event_data, events[event].event_data, 258 events[event].event_data_len); 259 260 status = efi_call_proto(tcg2, hash_log_extend_event, 0, 261 load_addr, load_size, &evt->event_data); 262 efi_bs_call(free_pool, evt); 263 264 if (status != EFI_SUCCESS) 265 goto fail; 266 return EFI_SUCCESS; 267 } 268 269 return EFI_UNSUPPORTED; 270 fail: 271 efi_warn("Failed to measure data for event %d: 0x%lx\n", event, status); 272 return status; 273 } 274 275 /* 276 * Convert the unicode UEFI command line to ASCII to pass to kernel. 277 * Size of memory allocated return in *cmd_line_len. 278 * Returns NULL on error. 279 */ 280 char *efi_convert_cmdline(efi_loaded_image_t *image, int *cmd_line_len) 281 { 282 const efi_char16_t *options = efi_table_attr(image, load_options); 283 u32 options_size = efi_table_attr(image, load_options_size); 284 int options_bytes = 0, safe_options_bytes = 0; /* UTF-8 bytes */ 285 unsigned long cmdline_addr = 0; 286 const efi_char16_t *s2; 287 bool in_quote = false; 288 efi_status_t status; 289 u32 options_chars; 290 291 if (options_size > 0) 292 efi_measure_tagged_event((unsigned long)options, options_size, 293 EFISTUB_EVT_LOAD_OPTIONS); 294 295 efi_apply_loadoptions_quirk((const void **)&options, &options_size); 296 options_chars = options_size / sizeof(efi_char16_t); 297 298 if (options) { 299 s2 = options; 300 while (options_bytes < COMMAND_LINE_SIZE && options_chars--) { 301 efi_char16_t c = *s2++; 302 303 if (c < 0x80) { 304 if (c == L'\0' || c == L'\n') 305 break; 306 if (c == L'"') 307 in_quote = !in_quote; 308 else if (!in_quote && isspace((char)c)) 309 safe_options_bytes = options_bytes; 310 311 options_bytes++; 312 continue; 313 } 314 315 /* 316 * Get the number of UTF-8 bytes corresponding to a 317 * UTF-16 character. 318 * The first part handles everything in the BMP. 319 */ 320 options_bytes += 2 + (c >= 0x800); 321 /* 322 * Add one more byte for valid surrogate pairs. Invalid 323 * surrogates will be replaced with 0xfffd and take up 324 * only 3 bytes. 325 */ 326 if ((c & 0xfc00) == 0xd800) { 327 /* 328 * If the very last word is a high surrogate, 329 * we must ignore it since we can't access the 330 * low surrogate. 331 */ 332 if (!options_chars) { 333 options_bytes -= 3; 334 } else if ((*s2 & 0xfc00) == 0xdc00) { 335 options_bytes++; 336 options_chars--; 337 s2++; 338 } 339 } 340 } 341 if (options_bytes >= COMMAND_LINE_SIZE) { 342 options_bytes = safe_options_bytes; 343 efi_err("Command line is too long: truncated to %d bytes\n", 344 options_bytes); 345 } 346 } 347 348 options_bytes++; /* NUL termination */ 349 350 status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, options_bytes, 351 (void **)&cmdline_addr); 352 if (status != EFI_SUCCESS) 353 return NULL; 354 355 snprintf((char *)cmdline_addr, options_bytes, "%.*ls", 356 options_bytes - 1, options); 357 358 *cmd_line_len = options_bytes; 359 return (char *)cmdline_addr; 360 } 361 362 /** 363 * efi_exit_boot_services() - Exit boot services 364 * @handle: handle of the exiting image 365 * @priv: argument to be passed to @priv_func 366 * @priv_func: function to process the memory map before exiting boot services 367 * 368 * Handle calling ExitBootServices according to the requirements set out by the 369 * spec. Obtains the current memory map, and returns that info after calling 370 * ExitBootServices. The client must specify a function to perform any 371 * processing of the memory map data prior to ExitBootServices. A client 372 * specific structure may be passed to the function via priv. The client 373 * function may be called multiple times. 374 * 375 * Return: status code 376 */ 377 efi_status_t efi_exit_boot_services(void *handle, void *priv, 378 efi_exit_boot_map_processing priv_func) 379 { 380 struct efi_boot_memmap *map; 381 efi_status_t status; 382 383 if (efi_disable_pci_dma) 384 efi_pci_disable_bridge_busmaster(); 385 386 status = efi_get_memory_map(&map, true); 387 if (status != EFI_SUCCESS) 388 return status; 389 390 status = priv_func(map, priv); 391 if (status != EFI_SUCCESS) { 392 efi_bs_call(free_pool, map); 393 return status; 394 } 395 396 status = efi_bs_call(exit_boot_services, handle, map->map_key); 397 398 if (status == EFI_INVALID_PARAMETER) { 399 /* 400 * The memory map changed between efi_get_memory_map() and 401 * exit_boot_services(). Per the UEFI Spec v2.6, Section 6.4: 402 * EFI_BOOT_SERVICES.ExitBootServices we need to get the 403 * updated map, and try again. The spec implies one retry 404 * should be sufficent, which is confirmed against the EDK2 405 * implementation. Per the spec, we can only invoke 406 * get_memory_map() and exit_boot_services() - we cannot alloc 407 * so efi_get_memory_map() cannot be used, and we must reuse 408 * the buffer. For all practical purposes, the headroom in the 409 * buffer should account for any changes in the map so the call 410 * to get_memory_map() is expected to succeed here. 411 */ 412 map->map_size = map->buff_size; 413 status = efi_bs_call(get_memory_map, 414 &map->map_size, 415 &map->map, 416 &map->map_key, 417 &map->desc_size, 418 &map->desc_ver); 419 420 /* exit_boot_services() was called, thus cannot free */ 421 if (status != EFI_SUCCESS) 422 return status; 423 424 status = priv_func(map, priv); 425 /* exit_boot_services() was called, thus cannot free */ 426 if (status != EFI_SUCCESS) 427 return status; 428 429 status = efi_bs_call(exit_boot_services, handle, map->map_key); 430 } 431 432 return status; 433 } 434 435 /** 436 * get_efi_config_table() - retrieve UEFI configuration table 437 * @guid: GUID of the configuration table to be retrieved 438 * Return: pointer to the configuration table or NULL 439 */ 440 void *get_efi_config_table(efi_guid_t guid) 441 { 442 unsigned long tables = efi_table_attr(efi_system_table, tables); 443 int nr_tables = efi_table_attr(efi_system_table, nr_tables); 444 int i; 445 446 for (i = 0; i < nr_tables; i++) { 447 efi_config_table_t *t = (void *)tables; 448 449 if (efi_guidcmp(t->guid, guid) == 0) 450 return efi_table_attr(t, table); 451 452 tables += efi_is_native() ? sizeof(efi_config_table_t) 453 : sizeof(efi_config_table_32_t); 454 } 455 return NULL; 456 } 457 458 /* 459 * The LINUX_EFI_INITRD_MEDIA_GUID vendor media device path below provides a way 460 * for the firmware or bootloader to expose the initrd data directly to the stub 461 * via the trivial LoadFile2 protocol, which is defined in the UEFI spec, and is 462 * very easy to implement. It is a simple Linux initrd specific conduit between 463 * kernel and firmware, allowing us to put the EFI stub (being part of the 464 * kernel) in charge of where and when to load the initrd, while leaving it up 465 * to the firmware to decide whether it needs to expose its filesystem hierarchy 466 * via EFI protocols. 467 */ 468 static const struct { 469 struct efi_vendor_dev_path vendor; 470 struct efi_generic_dev_path end; 471 } __packed initrd_dev_path = { 472 { 473 { 474 EFI_DEV_MEDIA, 475 EFI_DEV_MEDIA_VENDOR, 476 sizeof(struct efi_vendor_dev_path), 477 }, 478 LINUX_EFI_INITRD_MEDIA_GUID 479 }, { 480 EFI_DEV_END_PATH, 481 EFI_DEV_END_ENTIRE, 482 sizeof(struct efi_generic_dev_path) 483 } 484 }; 485 486 /** 487 * efi_load_initrd_dev_path() - load the initrd from the Linux initrd device path 488 * @initrd: pointer of struct to store the address where the initrd was loaded 489 * and the size of the loaded initrd 490 * @max: upper limit for the initrd memory allocation 491 * 492 * Return: 493 * * %EFI_SUCCESS if the initrd was loaded successfully, in which 494 * case @load_addr and @load_size are assigned accordingly 495 * * %EFI_NOT_FOUND if no LoadFile2 protocol exists on the initrd device path 496 * * %EFI_OUT_OF_RESOURCES if memory allocation failed 497 * * %EFI_LOAD_ERROR in all other cases 498 */ 499 static 500 efi_status_t efi_load_initrd_dev_path(struct linux_efi_initrd *initrd, 501 unsigned long max) 502 { 503 efi_guid_t lf2_proto_guid = EFI_LOAD_FILE2_PROTOCOL_GUID; 504 efi_device_path_protocol_t *dp; 505 efi_load_file2_protocol_t *lf2; 506 efi_handle_t handle; 507 efi_status_t status; 508 509 dp = (efi_device_path_protocol_t *)&initrd_dev_path; 510 status = efi_bs_call(locate_device_path, &lf2_proto_guid, &dp, &handle); 511 if (status != EFI_SUCCESS) 512 return status; 513 514 status = efi_bs_call(handle_protocol, handle, &lf2_proto_guid, 515 (void **)&lf2); 516 if (status != EFI_SUCCESS) 517 return status; 518 519 initrd->size = 0; 520 status = efi_call_proto(lf2, load_file, dp, false, &initrd->size, NULL); 521 if (status != EFI_BUFFER_TOO_SMALL) 522 return EFI_LOAD_ERROR; 523 524 status = efi_allocate_pages(initrd->size, &initrd->base, max); 525 if (status != EFI_SUCCESS) 526 return status; 527 528 status = efi_call_proto(lf2, load_file, dp, false, &initrd->size, 529 (void *)initrd->base); 530 if (status != EFI_SUCCESS) { 531 efi_free(initrd->size, initrd->base); 532 return EFI_LOAD_ERROR; 533 } 534 return EFI_SUCCESS; 535 } 536 537 static 538 efi_status_t efi_load_initrd_cmdline(efi_loaded_image_t *image, 539 struct linux_efi_initrd *initrd, 540 unsigned long soft_limit, 541 unsigned long hard_limit) 542 { 543 if (image == NULL) 544 return EFI_UNSUPPORTED; 545 546 return handle_cmdline_files(image, L"initrd=", sizeof(L"initrd=") - 2, 547 soft_limit, hard_limit, 548 &initrd->base, &initrd->size); 549 } 550 551 /** 552 * efi_load_initrd() - Load initial RAM disk 553 * @image: EFI loaded image protocol 554 * @soft_limit: preferred address for loading the initrd 555 * @hard_limit: upper limit address for loading the initrd 556 * 557 * Return: status code 558 */ 559 efi_status_t efi_load_initrd(efi_loaded_image_t *image, 560 unsigned long soft_limit, 561 unsigned long hard_limit, 562 const struct linux_efi_initrd **out) 563 { 564 efi_guid_t tbl_guid = LINUX_EFI_INITRD_MEDIA_GUID; 565 efi_status_t status = EFI_SUCCESS; 566 struct linux_efi_initrd initrd, *tbl; 567 568 if (!IS_ENABLED(CONFIG_BLK_DEV_INITRD) || efi_noinitrd) 569 return EFI_SUCCESS; 570 571 status = efi_load_initrd_dev_path(&initrd, hard_limit); 572 if (status == EFI_SUCCESS) { 573 efi_info("Loaded initrd from LINUX_EFI_INITRD_MEDIA_GUID device path\n"); 574 if (initrd.size > 0 && 575 efi_measure_tagged_event(initrd.base, initrd.size, 576 EFISTUB_EVT_INITRD) == EFI_SUCCESS) 577 efi_info("Measured initrd data into PCR 9\n"); 578 } else if (status == EFI_NOT_FOUND) { 579 status = efi_load_initrd_cmdline(image, &initrd, soft_limit, 580 hard_limit); 581 /* command line loader disabled or no initrd= passed? */ 582 if (status == EFI_UNSUPPORTED || status == EFI_NOT_READY) 583 return EFI_SUCCESS; 584 if (status == EFI_SUCCESS) 585 efi_info("Loaded initrd from command line option\n"); 586 } 587 if (status != EFI_SUCCESS) 588 goto failed; 589 590 status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, sizeof(initrd), 591 (void **)&tbl); 592 if (status != EFI_SUCCESS) 593 goto free_initrd; 594 595 *tbl = initrd; 596 status = efi_bs_call(install_configuration_table, &tbl_guid, tbl); 597 if (status != EFI_SUCCESS) 598 goto free_tbl; 599 600 if (out) 601 *out = tbl; 602 return EFI_SUCCESS; 603 604 free_tbl: 605 efi_bs_call(free_pool, tbl); 606 free_initrd: 607 efi_free(initrd.size, initrd.base); 608 failed: 609 efi_err("Failed to load initrd: 0x%lx\n", status); 610 return status; 611 } 612 613 /** 614 * efi_wait_for_key() - Wait for key stroke 615 * @usec: number of microseconds to wait for key stroke 616 * @key: key entered 617 * 618 * Wait for up to @usec microseconds for a key stroke. 619 * 620 * Return: status code, EFI_SUCCESS if key received 621 */ 622 efi_status_t efi_wait_for_key(unsigned long usec, efi_input_key_t *key) 623 { 624 efi_event_t events[2], timer; 625 unsigned long index; 626 efi_simple_text_input_protocol_t *con_in; 627 efi_status_t status; 628 629 con_in = efi_table_attr(efi_system_table, con_in); 630 if (!con_in) 631 return EFI_UNSUPPORTED; 632 efi_set_event_at(events, 0, efi_table_attr(con_in, wait_for_key)); 633 634 status = efi_bs_call(create_event, EFI_EVT_TIMER, 0, NULL, NULL, &timer); 635 if (status != EFI_SUCCESS) 636 return status; 637 638 status = efi_bs_call(set_timer, timer, EfiTimerRelative, 639 EFI_100NSEC_PER_USEC * usec); 640 if (status != EFI_SUCCESS) 641 return status; 642 efi_set_event_at(events, 1, timer); 643 644 status = efi_bs_call(wait_for_event, 2, events, &index); 645 if (status == EFI_SUCCESS) { 646 if (index == 0) 647 status = efi_call_proto(con_in, read_keystroke, key); 648 else 649 status = EFI_TIMEOUT; 650 } 651 652 efi_bs_call(close_event, timer); 653 654 return status; 655 } 656 657 /** 658 * efi_remap_image - Remap a loaded image with the appropriate permissions 659 * for code and data 660 * 661 * @image_base: the base of the image in memory 662 * @alloc_size: the size of the area in memory occupied by the image 663 * @code_size: the size of the leading part of the image containing code 664 * and read-only data 665 * 666 * efi_remap_image() uses the EFI memory attribute protocol to remap the code 667 * region of the loaded image read-only/executable, and the remainder 668 * read-write/non-executable. The code region is assumed to start at the base 669 * of the image, and will therefore cover the PE/COFF header as well. 670 */ 671 void efi_remap_image(unsigned long image_base, unsigned alloc_size, 672 unsigned long code_size) 673 { 674 efi_guid_t guid = EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID; 675 efi_memory_attribute_protocol_t *memattr; 676 efi_status_t status; 677 u64 attr; 678 679 /* 680 * If the firmware implements the EFI_MEMORY_ATTRIBUTE_PROTOCOL, let's 681 * invoke it to remap the text/rodata region of the decompressed image 682 * as read-only and the data/bss region as non-executable. 683 */ 684 status = efi_bs_call(locate_protocol, &guid, NULL, (void **)&memattr); 685 if (status != EFI_SUCCESS) 686 return; 687 688 // Get the current attributes for the entire region 689 status = memattr->get_memory_attributes(memattr, image_base, 690 alloc_size, &attr); 691 if (status != EFI_SUCCESS) { 692 efi_warn("Failed to retrieve memory attributes for image region: 0x%lx\n", 693 status); 694 return; 695 } 696 697 // Mark the code region as read-only 698 status = memattr->set_memory_attributes(memattr, image_base, code_size, 699 EFI_MEMORY_RO); 700 if (status != EFI_SUCCESS) { 701 efi_warn("Failed to remap code region read-only\n"); 702 return; 703 } 704 705 // If the entire region was already mapped as non-exec, clear the 706 // attribute from the code region. Otherwise, set it on the data 707 // region. 708 if (attr & EFI_MEMORY_XP) { 709 status = memattr->clear_memory_attributes(memattr, image_base, 710 code_size, 711 EFI_MEMORY_XP); 712 if (status != EFI_SUCCESS) 713 efi_warn("Failed to remap code region executable\n"); 714 } else { 715 status = memattr->set_memory_attributes(memattr, 716 image_base + code_size, 717 alloc_size - code_size, 718 EFI_MEMORY_XP); 719 if (status != EFI_SUCCESS) 720 efi_warn("Failed to remap data region non-executable\n"); 721 } 722 } 723