14febfb8dSArd Biesheuvel // SPDX-License-Identifier: GPL-2.0 2f4f75ad5SArd Biesheuvel /* 3f4f75ad5SArd Biesheuvel * Helper functions used by the EFI stub on multiple 4f4f75ad5SArd Biesheuvel * architectures. This should be #included by the EFI stub 5f4f75ad5SArd Biesheuvel * implementation files. 6f4f75ad5SArd Biesheuvel * 7f4f75ad5SArd Biesheuvel * Copyright 2011 Intel Corporation; author Matt Fleming 8f4f75ad5SArd Biesheuvel */ 9f4f75ad5SArd Biesheuvel 10c0891ac1SAlexey Dobriyan #include <linux/stdarg.h> 112c7d1e30SArvind Sankar 12f4f75ad5SArd Biesheuvel #include <linux/efi.h> 13fd0528a2SArvind Sankar #include <linux/kernel.h> 14f4f75ad5SArd Biesheuvel #include <asm/efi.h> 1580b1bfe1SArvind Sankar #include <asm/setup.h> 16f4f75ad5SArd Biesheuvel 17f4f75ad5SArd Biesheuvel #include "efistub.h" 18f4f75ad5SArd Biesheuvel 19980771f6SArd Biesheuvel bool efi_nochunk; 207c116db2SWill Deacon bool efi_nokaslr = !IS_ENABLED(CONFIG_RANDOMIZE_BASE); 21980771f6SArd Biesheuvel bool efi_novamap; 22980771f6SArd Biesheuvel 2320287d56SArd Biesheuvel static bool efi_noinitrd; 2454439370SArvind Sankar static bool efi_nosoftreserve; 2554439370SArvind Sankar static bool efi_disable_pci_dma = IS_ENABLED(CONFIG_EFI_DISABLE_PCI_DMA); 2660f38de7SArd Biesheuvel 27b617c526SDan Williams bool __pure __efi_soft_reserve_enabled(void) 28b617c526SDan Williams { 29b617c526SDan Williams return !efi_nosoftreserve; 30b617c526SDan Williams } 3160f38de7SArd Biesheuvel 328c0a839cSHeinrich Schuchardt /** 338c0a839cSHeinrich Schuchardt * efi_parse_options() - Parse EFI command line options 348c0a839cSHeinrich Schuchardt * @cmdline: kernel command line 358c0a839cSHeinrich Schuchardt * 368c0a839cSHeinrich Schuchardt * Parse the ASCII string @cmdline for EFI options, denoted by the efi= 375a17dae4SMatt Fleming * option, e.g. efi=nochunk. 385a17dae4SMatt Fleming * 395a17dae4SMatt Fleming * It should be noted that efi= is parsed in two very different 405a17dae4SMatt Fleming * environments, first in the early boot environment of the EFI boot 415a17dae4SMatt Fleming * stub, and subsequently during the kernel boot. 428c0a839cSHeinrich Schuchardt * 438c0a839cSHeinrich Schuchardt * Return: status code 445a17dae4SMatt Fleming */ 4560f38de7SArd Biesheuvel efi_status_t efi_parse_options(char const *cmdline) 465a17dae4SMatt Fleming { 47a37ca6a2SArvind Sankar size_t len; 4891d150c0SArd Biesheuvel efi_status_t status; 4991d150c0SArd Biesheuvel char *str, *buf; 505a17dae4SMatt Fleming 51a37ca6a2SArvind Sankar if (!cmdline) 52a37ca6a2SArvind Sankar return EFI_SUCCESS; 53a37ca6a2SArvind Sankar 548a8a3237SArvind Sankar len = strnlen(cmdline, COMMAND_LINE_SIZE - 1) + 1; 5591d150c0SArd Biesheuvel status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, len, (void **)&buf); 5691d150c0SArd Biesheuvel if (status != EFI_SUCCESS) 5791d150c0SArd Biesheuvel return status; 5891d150c0SArd Biesheuvel 598a8a3237SArvind Sankar memcpy(buf, cmdline, len - 1); 608a8a3237SArvind Sankar buf[len - 1] = '\0'; 618a8a3237SArvind Sankar str = skip_spaces(buf); 6291d150c0SArd Biesheuvel 6391d150c0SArd Biesheuvel while (*str) { 6491d150c0SArd Biesheuvel char *param, *val; 6591d150c0SArd Biesheuvel 6691d150c0SArd Biesheuvel str = next_arg(str, ¶m, &val); 671fd9717dSArvind Sankar if (!val && !strcmp(param, "--")) 681fd9717dSArvind Sankar break; 6991d150c0SArd Biesheuvel 7091d150c0SArd Biesheuvel if (!strcmp(param, "nokaslr")) { 717d4e323dSArd Biesheuvel efi_nokaslr = true; 7291d150c0SArd Biesheuvel } else if (!strcmp(param, "quiet")) { 7323d5b73fSArvind Sankar efi_loglevel = CONSOLE_LOGLEVEL_QUIET; 7479d3219dSArd Biesheuvel } else if (!strcmp(param, "noinitrd")) { 7579d3219dSArd Biesheuvel efi_noinitrd = true; 76*cb1c9e02SArd Biesheuvel } else if (IS_ENABLED(CONFIG_X86_64) && !strcmp(param, "no5lvl")) { 77*cb1c9e02SArd Biesheuvel efi_no5lvl = true; 7891d150c0SArd Biesheuvel } else if (!strcmp(param, "efi") && val) { 7991d150c0SArd Biesheuvel efi_nochunk = parse_option_str(val, "nochunk"); 80d3549a93SArd Biesheuvel efi_novamap |= parse_option_str(val, "novamap"); 81eeff7d63SArd Biesheuvel 8291d150c0SArd Biesheuvel efi_nosoftreserve = IS_ENABLED(CONFIG_EFI_SOFT_RESERVE) && 8391d150c0SArd Biesheuvel parse_option_str(val, "nosoftreserve"); 845a17dae4SMatt Fleming 8591d150c0SArd Biesheuvel if (parse_option_str(val, "disable_early_pci_dma")) 864444f854SMatthew Garrett efi_disable_pci_dma = true; 8791d150c0SArd Biesheuvel if (parse_option_str(val, "no_disable_early_pci_dma")) 884444f854SMatthew Garrett efi_disable_pci_dma = false; 8923d5b73fSArvind Sankar if (parse_option_str(val, "debug")) 9023d5b73fSArvind Sankar efi_loglevel = CONSOLE_LOGLEVEL_DEBUG; 91fffb6804SArvind Sankar } else if (!strcmp(param, "video") && 92fffb6804SArvind Sankar val && strstarts(val, "efifb:")) { 93fffb6804SArvind Sankar efi_parse_option_graphics(val + strlen("efifb:")); 944444f854SMatthew Garrett } 955a17dae4SMatt Fleming } 9691d150c0SArd Biesheuvel efi_bs_call(free_pool, buf); 975a17dae4SMatt Fleming return EFI_SUCCESS; 985a17dae4SMatt Fleming } 99f4f75ad5SArd Biesheuvel 100f4f75ad5SArd Biesheuvel /* 1014a568ce2SArvind Sankar * The EFI_LOAD_OPTION descriptor has the following layout: 1024a568ce2SArvind Sankar * u32 Attributes; 1034a568ce2SArvind Sankar * u16 FilePathListLength; 1044a568ce2SArvind Sankar * u16 Description[]; 1054a568ce2SArvind Sankar * efi_device_path_protocol_t FilePathList[]; 1064a568ce2SArvind Sankar * u8 OptionalData[]; 1074a568ce2SArvind Sankar * 1084a568ce2SArvind Sankar * This function validates and unpacks the variable-size data fields. 1094a568ce2SArvind Sankar */ 1104a568ce2SArvind Sankar static 1114a568ce2SArvind Sankar bool efi_load_option_unpack(efi_load_option_unpacked_t *dest, 1124a568ce2SArvind Sankar const efi_load_option_t *src, size_t size) 1134a568ce2SArvind Sankar { 1144a568ce2SArvind Sankar const void *pos; 1154a568ce2SArvind Sankar u16 c; 1164a568ce2SArvind Sankar efi_device_path_protocol_t header; 1174a568ce2SArvind Sankar const efi_char16_t *description; 1184a568ce2SArvind Sankar const efi_device_path_protocol_t *file_path_list; 1194a568ce2SArvind Sankar 1204a568ce2SArvind Sankar if (size < offsetof(efi_load_option_t, variable_data)) 1214a568ce2SArvind Sankar return false; 1224a568ce2SArvind Sankar pos = src->variable_data; 1234a568ce2SArvind Sankar size -= offsetof(efi_load_option_t, variable_data); 1244a568ce2SArvind Sankar 1254a568ce2SArvind Sankar if ((src->attributes & ~EFI_LOAD_OPTION_MASK) != 0) 1264a568ce2SArvind Sankar return false; 1274a568ce2SArvind Sankar 1284a568ce2SArvind Sankar /* Scan description. */ 1294a568ce2SArvind Sankar description = pos; 1304a568ce2SArvind Sankar do { 1314a568ce2SArvind Sankar if (size < sizeof(c)) 1324a568ce2SArvind Sankar return false; 1334a568ce2SArvind Sankar c = *(const u16 *)pos; 1344a568ce2SArvind Sankar pos += sizeof(c); 1354a568ce2SArvind Sankar size -= sizeof(c); 1364a568ce2SArvind Sankar } while (c != L'\0'); 1374a568ce2SArvind Sankar 1384a568ce2SArvind Sankar /* Scan file_path_list. */ 1394a568ce2SArvind Sankar file_path_list = pos; 1404a568ce2SArvind Sankar do { 1414a568ce2SArvind Sankar if (size < sizeof(header)) 1424a568ce2SArvind Sankar return false; 1434a568ce2SArvind Sankar header = *(const efi_device_path_protocol_t *)pos; 1444a568ce2SArvind Sankar if (header.length < sizeof(header)) 1454a568ce2SArvind Sankar return false; 1464a568ce2SArvind Sankar if (size < header.length) 1474a568ce2SArvind Sankar return false; 1484a568ce2SArvind Sankar pos += header.length; 1494a568ce2SArvind Sankar size -= header.length; 1504a568ce2SArvind Sankar } while ((header.type != EFI_DEV_END_PATH && header.type != EFI_DEV_END_PATH2) || 1514a568ce2SArvind Sankar (header.sub_type != EFI_DEV_END_ENTIRE)); 1524a568ce2SArvind Sankar if (pos != (const void *)file_path_list + src->file_path_list_length) 1534a568ce2SArvind Sankar return false; 1544a568ce2SArvind Sankar 1554a568ce2SArvind Sankar dest->attributes = src->attributes; 1564a568ce2SArvind Sankar dest->file_path_list_length = src->file_path_list_length; 1574a568ce2SArvind Sankar dest->description = description; 1584a568ce2SArvind Sankar dest->file_path_list = file_path_list; 1594a568ce2SArvind Sankar dest->optional_data_size = size; 1604a568ce2SArvind Sankar dest->optional_data = size ? pos : NULL; 1614a568ce2SArvind Sankar 1624a568ce2SArvind Sankar return true; 1634a568ce2SArvind Sankar } 1644a568ce2SArvind Sankar 1654a568ce2SArvind Sankar /* 1664a568ce2SArvind Sankar * At least some versions of Dell firmware pass the entire contents of the 1674a568ce2SArvind Sankar * Boot#### variable, i.e. the EFI_LOAD_OPTION descriptor, rather than just the 1684a568ce2SArvind Sankar * OptionalData field. 1694a568ce2SArvind Sankar * 1704a568ce2SArvind Sankar * Detect this case and extract OptionalData. 1714a568ce2SArvind Sankar */ 172a241d94bSArd Biesheuvel void efi_apply_loadoptions_quirk(const void **load_options, u32 *load_options_size) 1734a568ce2SArvind Sankar { 1744a568ce2SArvind Sankar const efi_load_option_t *load_option = *load_options; 1754a568ce2SArvind Sankar efi_load_option_unpacked_t load_option_unpacked; 1764a568ce2SArvind Sankar 1774a568ce2SArvind Sankar if (!IS_ENABLED(CONFIG_X86)) 1784a568ce2SArvind Sankar return; 1794a568ce2SArvind Sankar if (!load_option) 1804a568ce2SArvind Sankar return; 1814a568ce2SArvind Sankar if (*load_options_size < sizeof(*load_option)) 1824a568ce2SArvind Sankar return; 1834a568ce2SArvind Sankar if ((load_option->attributes & ~EFI_LOAD_OPTION_BOOT_MASK) != 0) 1844a568ce2SArvind Sankar return; 1854a568ce2SArvind Sankar 1864a568ce2SArvind Sankar if (!efi_load_option_unpack(&load_option_unpacked, load_option, *load_options_size)) 1874a568ce2SArvind Sankar return; 1884a568ce2SArvind Sankar 1894a568ce2SArvind Sankar efi_warn_once(FW_BUG "LoadOptions is an EFI_LOAD_OPTION descriptor\n"); 1904a568ce2SArvind Sankar efi_warn_once(FW_BUG "Using OptionalData as a workaround\n"); 1914a568ce2SArvind Sankar 1924a568ce2SArvind Sankar *load_options = load_option_unpacked.optional_data; 1934a568ce2SArvind Sankar *load_options_size = load_option_unpacked.optional_data_size; 1944a568ce2SArvind Sankar } 1954a568ce2SArvind Sankar 19656633169SIlias Apalodimas enum efistub_event { 19756633169SIlias Apalodimas EFISTUB_EVT_INITRD, 19871c7adc9SIlias Apalodimas EFISTUB_EVT_LOAD_OPTIONS, 19956633169SIlias Apalodimas EFISTUB_EVT_COUNT, 20056633169SIlias Apalodimas }; 20156633169SIlias Apalodimas 20256633169SIlias Apalodimas #define STR_WITH_SIZE(s) sizeof(s), s 20356633169SIlias Apalodimas 20456633169SIlias Apalodimas static const struct { 20556633169SIlias Apalodimas u32 pcr_index; 20656633169SIlias Apalodimas u32 event_id; 20756633169SIlias Apalodimas u32 event_data_len; 20856633169SIlias Apalodimas u8 event_data[52]; 20956633169SIlias Apalodimas } events[] = { 21056633169SIlias Apalodimas [EFISTUB_EVT_INITRD] = { 21156633169SIlias Apalodimas 9, 21256633169SIlias Apalodimas INITRD_EVENT_TAG_ID, 21356633169SIlias Apalodimas STR_WITH_SIZE("Linux initrd") 21456633169SIlias Apalodimas }, 21571c7adc9SIlias Apalodimas [EFISTUB_EVT_LOAD_OPTIONS] = { 21671c7adc9SIlias Apalodimas 9, 21771c7adc9SIlias Apalodimas LOAD_OPTIONS_EVENT_TAG_ID, 21871c7adc9SIlias Apalodimas STR_WITH_SIZE("LOADED_IMAGE::LoadOptions") 21971c7adc9SIlias Apalodimas }, 22056633169SIlias Apalodimas }; 22156633169SIlias Apalodimas 22256633169SIlias Apalodimas static efi_status_t efi_measure_tagged_event(unsigned long load_addr, 22356633169SIlias Apalodimas unsigned long load_size, 22456633169SIlias Apalodimas enum efistub_event event) 22556633169SIlias Apalodimas { 22656633169SIlias Apalodimas efi_guid_t tcg2_guid = EFI_TCG2_PROTOCOL_GUID; 22756633169SIlias Apalodimas efi_tcg2_protocol_t *tcg2 = NULL; 22856633169SIlias Apalodimas efi_status_t status; 22956633169SIlias Apalodimas 23056633169SIlias Apalodimas efi_bs_call(locate_protocol, &tcg2_guid, NULL, (void **)&tcg2); 23156633169SIlias Apalodimas if (tcg2) { 23256633169SIlias Apalodimas struct efi_measured_event { 23356633169SIlias Apalodimas efi_tcg2_event_t event_data; 23456633169SIlias Apalodimas efi_tcg2_tagged_event_t tagged_event; 23556633169SIlias Apalodimas u8 tagged_event_data[]; 23656633169SIlias Apalodimas } *evt; 23756633169SIlias Apalodimas int size = sizeof(*evt) + events[event].event_data_len; 23856633169SIlias Apalodimas 23956633169SIlias Apalodimas status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, size, 24056633169SIlias Apalodimas (void **)&evt); 24156633169SIlias Apalodimas if (status != EFI_SUCCESS) 24256633169SIlias Apalodimas goto fail; 24356633169SIlias Apalodimas 24456633169SIlias Apalodimas evt->event_data = (struct efi_tcg2_event){ 24556633169SIlias Apalodimas .event_size = size, 24656633169SIlias Apalodimas .event_header.header_size = sizeof(evt->event_data.event_header), 24756633169SIlias Apalodimas .event_header.header_version = EFI_TCG2_EVENT_HEADER_VERSION, 24856633169SIlias Apalodimas .event_header.pcr_index = events[event].pcr_index, 24956633169SIlias Apalodimas .event_header.event_type = EV_EVENT_TAG, 25056633169SIlias Apalodimas }; 25156633169SIlias Apalodimas 25256633169SIlias Apalodimas evt->tagged_event = (struct efi_tcg2_tagged_event){ 25356633169SIlias Apalodimas .tagged_event_id = events[event].event_id, 25456633169SIlias Apalodimas .tagged_event_data_size = events[event].event_data_len, 25556633169SIlias Apalodimas }; 25656633169SIlias Apalodimas 25756633169SIlias Apalodimas memcpy(evt->tagged_event_data, events[event].event_data, 25856633169SIlias Apalodimas events[event].event_data_len); 25956633169SIlias Apalodimas 26056633169SIlias Apalodimas status = efi_call_proto(tcg2, hash_log_extend_event, 0, 26156633169SIlias Apalodimas load_addr, load_size, &evt->event_data); 26256633169SIlias Apalodimas efi_bs_call(free_pool, evt); 26356633169SIlias Apalodimas 26456633169SIlias Apalodimas if (status != EFI_SUCCESS) 26556633169SIlias Apalodimas goto fail; 26656633169SIlias Apalodimas return EFI_SUCCESS; 26756633169SIlias Apalodimas } 26856633169SIlias Apalodimas 26956633169SIlias Apalodimas return EFI_UNSUPPORTED; 27056633169SIlias Apalodimas fail: 27156633169SIlias Apalodimas efi_warn("Failed to measure data for event %d: 0x%lx\n", event, status); 27256633169SIlias Apalodimas return status; 27356633169SIlias Apalodimas } 27456633169SIlias Apalodimas 2754a568ce2SArvind Sankar /* 276f4f75ad5SArd Biesheuvel * Convert the unicode UEFI command line to ASCII to pass to kernel. 277f4f75ad5SArd Biesheuvel * Size of memory allocated return in *cmd_line_len. 278f4f75ad5SArd Biesheuvel * Returns NULL on error. 279f4f75ad5SArd Biesheuvel */ 28027cd5511SArd Biesheuvel char *efi_convert_cmdline(efi_loaded_image_t *image, int *cmd_line_len) 281f4f75ad5SArd Biesheuvel { 282a241d94bSArd Biesheuvel const efi_char16_t *options = efi_table_attr(image, load_options); 283a241d94bSArd Biesheuvel u32 options_size = efi_table_attr(image, load_options_size); 28480b1bfe1SArvind Sankar int options_bytes = 0, safe_options_bytes = 0; /* UTF-8 bytes */ 285a241d94bSArd Biesheuvel unsigned long cmdline_addr = 0; 286a241d94bSArd Biesheuvel const efi_char16_t *s2; 28780b1bfe1SArvind Sankar bool in_quote = false; 288f4f75ad5SArd Biesheuvel efi_status_t status; 289a241d94bSArd Biesheuvel u32 options_chars; 290f4f75ad5SArd Biesheuvel 29171c7adc9SIlias Apalodimas if (options_size > 0) 29271c7adc9SIlias Apalodimas efi_measure_tagged_event((unsigned long)options, options_size, 29371c7adc9SIlias Apalodimas EFISTUB_EVT_LOAD_OPTIONS); 29471c7adc9SIlias Apalodimas 295a241d94bSArd Biesheuvel efi_apply_loadoptions_quirk((const void **)&options, &options_size); 296a241d94bSArd Biesheuvel options_chars = options_size / sizeof(efi_char16_t); 2974a568ce2SArvind Sankar 298f4f75ad5SArd Biesheuvel if (options) { 299f4f75ad5SArd Biesheuvel s2 = options; 30080b1bfe1SArvind Sankar while (options_bytes < COMMAND_LINE_SIZE && options_chars--) { 301a241d94bSArd Biesheuvel efi_char16_t c = *s2++; 30215c316bcSArvind Sankar 30380b1bfe1SArvind Sankar if (c < 0x80) { 30415c316bcSArvind Sankar if (c == L'\0' || c == L'\n') 30515c316bcSArvind Sankar break; 30680b1bfe1SArvind Sankar if (c == L'"') 30780b1bfe1SArvind Sankar in_quote = !in_quote; 30880b1bfe1SArvind Sankar else if (!in_quote && isspace((char)c)) 30980b1bfe1SArvind Sankar safe_options_bytes = options_bytes; 31080b1bfe1SArvind Sankar 31180b1bfe1SArvind Sankar options_bytes++; 31280b1bfe1SArvind Sankar continue; 31380b1bfe1SArvind Sankar } 31480b1bfe1SArvind Sankar 31515c316bcSArvind Sankar /* 31615c316bcSArvind Sankar * Get the number of UTF-8 bytes corresponding to a 31715c316bcSArvind Sankar * UTF-16 character. 31815c316bcSArvind Sankar * The first part handles everything in the BMP. 31915c316bcSArvind Sankar */ 32080b1bfe1SArvind Sankar options_bytes += 2 + (c >= 0x800); 32115c316bcSArvind Sankar /* 32215c316bcSArvind Sankar * Add one more byte for valid surrogate pairs. Invalid 32315c316bcSArvind Sankar * surrogates will be replaced with 0xfffd and take up 32415c316bcSArvind Sankar * only 3 bytes. 32515c316bcSArvind Sankar */ 32615c316bcSArvind Sankar if ((c & 0xfc00) == 0xd800) { 32715c316bcSArvind Sankar /* 32815c316bcSArvind Sankar * If the very last word is a high surrogate, 32915c316bcSArvind Sankar * we must ignore it since we can't access the 33015c316bcSArvind Sankar * low surrogate. 33115c316bcSArvind Sankar */ 33204b24409SArvind Sankar if (!options_chars) { 33315c316bcSArvind Sankar options_bytes -= 3; 33415c316bcSArvind Sankar } else if ((*s2 & 0xfc00) == 0xdc00) { 33515c316bcSArvind Sankar options_bytes++; 33604b24409SArvind Sankar options_chars--; 33715c316bcSArvind Sankar s2++; 33815c316bcSArvind Sankar } 33915c316bcSArvind Sankar } 340f4f75ad5SArd Biesheuvel } 34180b1bfe1SArvind Sankar if (options_bytes >= COMMAND_LINE_SIZE) { 34280b1bfe1SArvind Sankar options_bytes = safe_options_bytes; 34380b1bfe1SArvind Sankar efi_err("Command line is too long: truncated to %d bytes\n", 34480b1bfe1SArvind Sankar options_bytes); 34580b1bfe1SArvind Sankar } 346f4f75ad5SArd Biesheuvel } 347f4f75ad5SArd Biesheuvel 348f4f75ad5SArd Biesheuvel options_bytes++; /* NUL termination */ 349f4f75ad5SArd Biesheuvel 35027cd5511SArd Biesheuvel status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, options_bytes, 35127cd5511SArd Biesheuvel (void **)&cmdline_addr); 352f4f75ad5SArd Biesheuvel if (status != EFI_SUCCESS) 353f4f75ad5SArd Biesheuvel return NULL; 354f4f75ad5SArd Biesheuvel 35504b24409SArvind Sankar snprintf((char *)cmdline_addr, options_bytes, "%.*ls", 35604b24409SArvind Sankar options_bytes - 1, options); 357f4f75ad5SArd Biesheuvel 358f4f75ad5SArd Biesheuvel *cmd_line_len = options_bytes; 359f4f75ad5SArd Biesheuvel return (char *)cmdline_addr; 360f4f75ad5SArd Biesheuvel } 361fc07716bSJeffrey Hugo 3628c0a839cSHeinrich Schuchardt /** 3638c0a839cSHeinrich Schuchardt * efi_exit_boot_services() - Exit boot services 3648c0a839cSHeinrich Schuchardt * @handle: handle of the exiting image 3658c0a839cSHeinrich Schuchardt * @priv: argument to be passed to @priv_func 3668c0a839cSHeinrich Schuchardt * @priv_func: function to process the memory map before exiting boot services 3678c0a839cSHeinrich Schuchardt * 368fc07716bSJeffrey Hugo * Handle calling ExitBootServices according to the requirements set out by the 369fc07716bSJeffrey Hugo * spec. Obtains the current memory map, and returns that info after calling 370fc07716bSJeffrey Hugo * ExitBootServices. The client must specify a function to perform any 371fc07716bSJeffrey Hugo * processing of the memory map data prior to ExitBootServices. A client 372fc07716bSJeffrey Hugo * specific structure may be passed to the function via priv. The client 373fc07716bSJeffrey Hugo * function may be called multiple times. 3748c0a839cSHeinrich Schuchardt * 3758c0a839cSHeinrich Schuchardt * Return: status code 376fc07716bSJeffrey Hugo */ 377eab31265SArd Biesheuvel efi_status_t efi_exit_boot_services(void *handle, void *priv, 378fc07716bSJeffrey Hugo efi_exit_boot_map_processing priv_func) 379fc07716bSJeffrey Hugo { 380eab31265SArd Biesheuvel struct efi_boot_memmap *map; 381fc07716bSJeffrey Hugo efi_status_t status; 382fc07716bSJeffrey Hugo 3832e28a798SArd Biesheuvel if (efi_disable_pci_dma) 3842e28a798SArd Biesheuvel efi_pci_disable_bridge_busmaster(); 3852e28a798SArd Biesheuvel 386171539f5SArd Biesheuvel status = efi_get_memory_map(&map, true); 387fc07716bSJeffrey Hugo if (status != EFI_SUCCESS) 388a12b78b5SArd Biesheuvel return status; 389fc07716bSJeffrey Hugo 390cd33a5c1SArd Biesheuvel status = priv_func(map, priv); 391a12b78b5SArd Biesheuvel if (status != EFI_SUCCESS) { 392a12b78b5SArd Biesheuvel efi_bs_call(free_pool, map); 393a12b78b5SArd Biesheuvel return status; 394a12b78b5SArd Biesheuvel } 395fc07716bSJeffrey Hugo 396eab31265SArd Biesheuvel status = efi_bs_call(exit_boot_services, handle, map->map_key); 397fc07716bSJeffrey Hugo 398fc07716bSJeffrey Hugo if (status == EFI_INVALID_PARAMETER) { 399fc07716bSJeffrey Hugo /* 400fc07716bSJeffrey Hugo * The memory map changed between efi_get_memory_map() and 401fc07716bSJeffrey Hugo * exit_boot_services(). Per the UEFI Spec v2.6, Section 6.4: 402fc07716bSJeffrey Hugo * EFI_BOOT_SERVICES.ExitBootServices we need to get the 403fc07716bSJeffrey Hugo * updated map, and try again. The spec implies one retry 404fc07716bSJeffrey Hugo * should be sufficent, which is confirmed against the EDK2 405fc07716bSJeffrey Hugo * implementation. Per the spec, we can only invoke 406fc07716bSJeffrey Hugo * get_memory_map() and exit_boot_services() - we cannot alloc 407fc07716bSJeffrey Hugo * so efi_get_memory_map() cannot be used, and we must reuse 408fc07716bSJeffrey Hugo * the buffer. For all practical purposes, the headroom in the 409fc07716bSJeffrey Hugo * buffer should account for any changes in the map so the call 410fc07716bSJeffrey Hugo * to get_memory_map() is expected to succeed here. 411fc07716bSJeffrey Hugo */ 412eab31265SArd Biesheuvel map->map_size = map->buff_size; 413966291f6SArd Biesheuvel status = efi_bs_call(get_memory_map, 414eab31265SArd Biesheuvel &map->map_size, 415eab31265SArd Biesheuvel &map->map, 416eab31265SArd Biesheuvel &map->map_key, 417eab31265SArd Biesheuvel &map->desc_size, 418eab31265SArd Biesheuvel &map->desc_ver); 419fc07716bSJeffrey Hugo 420fc07716bSJeffrey Hugo /* exit_boot_services() was called, thus cannot free */ 421fc07716bSJeffrey Hugo if (status != EFI_SUCCESS) 422a12b78b5SArd Biesheuvel return status; 423fc07716bSJeffrey Hugo 424cd33a5c1SArd Biesheuvel status = priv_func(map, priv); 425fc07716bSJeffrey Hugo /* exit_boot_services() was called, thus cannot free */ 426fc07716bSJeffrey Hugo if (status != EFI_SUCCESS) 427a12b78b5SArd Biesheuvel return status; 428fc07716bSJeffrey Hugo 429eab31265SArd Biesheuvel status = efi_bs_call(exit_boot_services, handle, map->map_key); 430fc07716bSJeffrey Hugo } 431fc07716bSJeffrey Hugo 432fc07716bSJeffrey Hugo return status; 433fc07716bSJeffrey Hugo } 43482d736acSMatthew Garrett 4358c0a839cSHeinrich Schuchardt /** 4368c0a839cSHeinrich Schuchardt * get_efi_config_table() - retrieve UEFI configuration table 4378c0a839cSHeinrich Schuchardt * @guid: GUID of the configuration table to be retrieved 4388c0a839cSHeinrich Schuchardt * Return: pointer to the configuration table or NULL 4398c0a839cSHeinrich Schuchardt */ 440cd33a5c1SArd Biesheuvel void *get_efi_config_table(efi_guid_t guid) 44182d736acSMatthew Garrett { 442ccc27ae7SArd Biesheuvel unsigned long tables = efi_table_attr(efi_system_table, tables); 443ccc27ae7SArd Biesheuvel int nr_tables = efi_table_attr(efi_system_table, nr_tables); 444f958efe9SArd Biesheuvel int i; 445f958efe9SArd Biesheuvel 446f958efe9SArd Biesheuvel for (i = 0; i < nr_tables; i++) { 447f958efe9SArd Biesheuvel efi_config_table_t *t = (void *)tables; 448f958efe9SArd Biesheuvel 449f958efe9SArd Biesheuvel if (efi_guidcmp(t->guid, guid) == 0) 45099ea8b1dSArd Biesheuvel return efi_table_attr(t, table); 451f958efe9SArd Biesheuvel 452f958efe9SArd Biesheuvel tables += efi_is_native() ? sizeof(efi_config_table_t) 453f958efe9SArd Biesheuvel : sizeof(efi_config_table_32_t); 454f958efe9SArd Biesheuvel } 455f958efe9SArd Biesheuvel return NULL; 45682d736acSMatthew Garrett } 457dc29da14SArd Biesheuvel 458ec93fc37SArd Biesheuvel /* 459ec93fc37SArd Biesheuvel * The LINUX_EFI_INITRD_MEDIA_GUID vendor media device path below provides a way 460ec93fc37SArd Biesheuvel * for the firmware or bootloader to expose the initrd data directly to the stub 461ec93fc37SArd Biesheuvel * via the trivial LoadFile2 protocol, which is defined in the UEFI spec, and is 462ec93fc37SArd Biesheuvel * very easy to implement. It is a simple Linux initrd specific conduit between 463ec93fc37SArd Biesheuvel * kernel and firmware, allowing us to put the EFI stub (being part of the 464ec93fc37SArd Biesheuvel * kernel) in charge of where and when to load the initrd, while leaving it up 465ec93fc37SArd Biesheuvel * to the firmware to decide whether it needs to expose its filesystem hierarchy 466ec93fc37SArd Biesheuvel * via EFI protocols. 467ec93fc37SArd Biesheuvel */ 468ec93fc37SArd Biesheuvel static const struct { 469ec93fc37SArd Biesheuvel struct efi_vendor_dev_path vendor; 470ec93fc37SArd Biesheuvel struct efi_generic_dev_path end; 471ec93fc37SArd Biesheuvel } __packed initrd_dev_path = { 472ec93fc37SArd Biesheuvel { 473ec93fc37SArd Biesheuvel { 474ec93fc37SArd Biesheuvel EFI_DEV_MEDIA, 475ec93fc37SArd Biesheuvel EFI_DEV_MEDIA_VENDOR, 476ec93fc37SArd Biesheuvel sizeof(struct efi_vendor_dev_path), 477ec93fc37SArd Biesheuvel }, 478ec93fc37SArd Biesheuvel LINUX_EFI_INITRD_MEDIA_GUID 479ec93fc37SArd Biesheuvel }, { 480ec93fc37SArd Biesheuvel EFI_DEV_END_PATH, 481ec93fc37SArd Biesheuvel EFI_DEV_END_ENTIRE, 482ec93fc37SArd Biesheuvel sizeof(struct efi_generic_dev_path) 483ec93fc37SArd Biesheuvel } 484ec93fc37SArd Biesheuvel }; 485ec93fc37SArd Biesheuvel 486ec93fc37SArd Biesheuvel /** 4878c0a839cSHeinrich Schuchardt * efi_load_initrd_dev_path() - load the initrd from the Linux initrd device path 488d981a88cSJialin Zhang * @initrd: pointer of struct to store the address where the initrd was loaded 489d981a88cSJialin Zhang * and the size of the loaded initrd 490ec93fc37SArd Biesheuvel * @max: upper limit for the initrd memory allocation 4918c0a839cSHeinrich Schuchardt * 4928c0a839cSHeinrich Schuchardt * Return: 4938c0a839cSHeinrich Schuchardt * * %EFI_SUCCESS if the initrd was loaded successfully, in which 494ec93fc37SArd Biesheuvel * case @load_addr and @load_size are assigned accordingly 4958c0a839cSHeinrich Schuchardt * * %EFI_NOT_FOUND if no LoadFile2 protocol exists on the initrd device path 4968c0a839cSHeinrich Schuchardt * * %EFI_OUT_OF_RESOURCES if memory allocation failed 4978c0a839cSHeinrich Schuchardt * * %EFI_LOAD_ERROR in all other cases 498ec93fc37SArd Biesheuvel */ 499f61900fdSArvind Sankar static 500f4dc7fffSArd Biesheuvel efi_status_t efi_load_initrd_dev_path(struct linux_efi_initrd *initrd, 501ec93fc37SArd Biesheuvel unsigned long max) 502ec93fc37SArd Biesheuvel { 503ec93fc37SArd Biesheuvel efi_guid_t lf2_proto_guid = EFI_LOAD_FILE2_PROTOCOL_GUID; 504ec93fc37SArd Biesheuvel efi_device_path_protocol_t *dp; 505ec93fc37SArd Biesheuvel efi_load_file2_protocol_t *lf2; 506ec93fc37SArd Biesheuvel efi_handle_t handle; 507ec93fc37SArd Biesheuvel efi_status_t status; 508ec93fc37SArd Biesheuvel 509ec93fc37SArd Biesheuvel dp = (efi_device_path_protocol_t *)&initrd_dev_path; 510ec93fc37SArd Biesheuvel status = efi_bs_call(locate_device_path, &lf2_proto_guid, &dp, &handle); 511ec93fc37SArd Biesheuvel if (status != EFI_SUCCESS) 512ec93fc37SArd Biesheuvel return status; 513ec93fc37SArd Biesheuvel 514ec93fc37SArd Biesheuvel status = efi_bs_call(handle_protocol, handle, &lf2_proto_guid, 515ec93fc37SArd Biesheuvel (void **)&lf2); 516ec93fc37SArd Biesheuvel if (status != EFI_SUCCESS) 517ec93fc37SArd Biesheuvel return status; 518ec93fc37SArd Biesheuvel 519f4dc7fffSArd Biesheuvel initrd->size = 0; 520f4dc7fffSArd Biesheuvel status = efi_call_proto(lf2, load_file, dp, false, &initrd->size, NULL); 521ec93fc37SArd Biesheuvel if (status != EFI_BUFFER_TOO_SMALL) 522ec93fc37SArd Biesheuvel return EFI_LOAD_ERROR; 523ec93fc37SArd Biesheuvel 524f4dc7fffSArd Biesheuvel status = efi_allocate_pages(initrd->size, &initrd->base, max); 525ec93fc37SArd Biesheuvel if (status != EFI_SUCCESS) 526ec93fc37SArd Biesheuvel return status; 527ec93fc37SArd Biesheuvel 528f4dc7fffSArd Biesheuvel status = efi_call_proto(lf2, load_file, dp, false, &initrd->size, 529f4dc7fffSArd Biesheuvel (void *)initrd->base); 530ec93fc37SArd Biesheuvel if (status != EFI_SUCCESS) { 531f4dc7fffSArd Biesheuvel efi_free(initrd->size, initrd->base); 532ec93fc37SArd Biesheuvel return EFI_LOAD_ERROR; 533ec93fc37SArd Biesheuvel } 534ec93fc37SArd Biesheuvel return EFI_SUCCESS; 535ec93fc37SArd Biesheuvel } 536f61900fdSArvind Sankar 537f61900fdSArvind Sankar static 538f61900fdSArvind Sankar efi_status_t efi_load_initrd_cmdline(efi_loaded_image_t *image, 539f4dc7fffSArd Biesheuvel struct linux_efi_initrd *initrd, 540f61900fdSArvind Sankar unsigned long soft_limit, 541f61900fdSArvind Sankar unsigned long hard_limit) 542f61900fdSArvind Sankar { 543e346bebbSArd Biesheuvel if (image == NULL) 544f4dc7fffSArd Biesheuvel return EFI_UNSUPPORTED; 545f61900fdSArvind Sankar 546f61900fdSArvind Sankar return handle_cmdline_files(image, L"initrd=", sizeof(L"initrd=") - 2, 547f61900fdSArvind Sankar soft_limit, hard_limit, 548f4dc7fffSArd Biesheuvel &initrd->base, &initrd->size); 549f61900fdSArvind Sankar } 550f61900fdSArvind Sankar 5518c0a839cSHeinrich Schuchardt /** 5528c0a839cSHeinrich Schuchardt * efi_load_initrd() - Load initial RAM disk 5538c0a839cSHeinrich Schuchardt * @image: EFI loaded image protocol 554947228cbSAtish Patra * @soft_limit: preferred address for loading the initrd 555947228cbSAtish Patra * @hard_limit: upper limit address for loading the initrd 5568c0a839cSHeinrich Schuchardt * 5578c0a839cSHeinrich Schuchardt * Return: status code 5588c0a839cSHeinrich Schuchardt */ 559f61900fdSArvind Sankar efi_status_t efi_load_initrd(efi_loaded_image_t *image, 560f61900fdSArvind Sankar unsigned long soft_limit, 561f4dc7fffSArd Biesheuvel unsigned long hard_limit, 562f4dc7fffSArd Biesheuvel const struct linux_efi_initrd **out) 563f61900fdSArvind Sankar { 564f4dc7fffSArd Biesheuvel efi_guid_t tbl_guid = LINUX_EFI_INITRD_MEDIA_GUID; 565f4dc7fffSArd Biesheuvel efi_status_t status = EFI_SUCCESS; 566f4dc7fffSArd Biesheuvel struct linux_efi_initrd initrd, *tbl; 567f61900fdSArvind Sankar 568f4dc7fffSArd Biesheuvel if (!IS_ENABLED(CONFIG_BLK_DEV_INITRD) || efi_noinitrd) 569f4dc7fffSArd Biesheuvel return EFI_SUCCESS; 570f4dc7fffSArd Biesheuvel 571f4dc7fffSArd Biesheuvel status = efi_load_initrd_dev_path(&initrd, hard_limit); 572f61900fdSArvind Sankar if (status == EFI_SUCCESS) { 573f61900fdSArvind Sankar efi_info("Loaded initrd from LINUX_EFI_INITRD_MEDIA_GUID device path\n"); 57456633169SIlias Apalodimas if (initrd.size > 0 && 57556633169SIlias Apalodimas efi_measure_tagged_event(initrd.base, initrd.size, 57656633169SIlias Apalodimas EFISTUB_EVT_INITRD) == EFI_SUCCESS) 57756633169SIlias Apalodimas efi_info("Measured initrd data into PCR 9\n"); 578f61900fdSArvind Sankar } else if (status == EFI_NOT_FOUND) { 579f4dc7fffSArd Biesheuvel status = efi_load_initrd_cmdline(image, &initrd, soft_limit, 580f4dc7fffSArd Biesheuvel hard_limit); 581f4dc7fffSArd Biesheuvel /* command line loader disabled or no initrd= passed? */ 582f4dc7fffSArd Biesheuvel if (status == EFI_UNSUPPORTED || status == EFI_NOT_READY) 583f4dc7fffSArd Biesheuvel return EFI_SUCCESS; 584f4dc7fffSArd Biesheuvel if (status == EFI_SUCCESS) 585f61900fdSArvind Sankar efi_info("Loaded initrd from command line option\n"); 586f61900fdSArvind Sankar } 587f4dc7fffSArd Biesheuvel if (status != EFI_SUCCESS) 588f4dc7fffSArd Biesheuvel goto failed; 589f046fff8SIlias Apalodimas 590f4dc7fffSArd Biesheuvel status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, sizeof(initrd), 591f4dc7fffSArd Biesheuvel (void **)&tbl); 592f4dc7fffSArd Biesheuvel if (status != EFI_SUCCESS) 593f4dc7fffSArd Biesheuvel goto free_initrd; 594f4dc7fffSArd Biesheuvel 595f4dc7fffSArd Biesheuvel *tbl = initrd; 596f4dc7fffSArd Biesheuvel status = efi_bs_call(install_configuration_table, &tbl_guid, tbl); 597f4dc7fffSArd Biesheuvel if (status != EFI_SUCCESS) 598f4dc7fffSArd Biesheuvel goto free_tbl; 599f4dc7fffSArd Biesheuvel 600f4dc7fffSArd Biesheuvel if (out) 601f4dc7fffSArd Biesheuvel *out = tbl; 602f4dc7fffSArd Biesheuvel return EFI_SUCCESS; 603f4dc7fffSArd Biesheuvel 604f4dc7fffSArd Biesheuvel free_tbl: 605f4dc7fffSArd Biesheuvel efi_bs_call(free_pool, tbl); 606f4dc7fffSArd Biesheuvel free_initrd: 607f4dc7fffSArd Biesheuvel efi_free(initrd.size, initrd.base); 608f4dc7fffSArd Biesheuvel failed: 609f4dc7fffSArd Biesheuvel efi_err("Failed to load initrd: 0x%lx\n", status); 610f61900fdSArvind Sankar return status; 611f61900fdSArvind Sankar } 61214c574f3SArvind Sankar 6138c0a839cSHeinrich Schuchardt /** 6148c0a839cSHeinrich Schuchardt * efi_wait_for_key() - Wait for key stroke 6158c0a839cSHeinrich Schuchardt * @usec: number of microseconds to wait for key stroke 6168c0a839cSHeinrich Schuchardt * @key: key entered 6178c0a839cSHeinrich Schuchardt * 6188c0a839cSHeinrich Schuchardt * Wait for up to @usec microseconds for a key stroke. 6198c0a839cSHeinrich Schuchardt * 6208c0a839cSHeinrich Schuchardt * Return: status code, EFI_SUCCESS if key received 6218c0a839cSHeinrich Schuchardt */ 62214c574f3SArvind Sankar efi_status_t efi_wait_for_key(unsigned long usec, efi_input_key_t *key) 62314c574f3SArvind Sankar { 62414c574f3SArvind Sankar efi_event_t events[2], timer; 62514c574f3SArvind Sankar unsigned long index; 62614c574f3SArvind Sankar efi_simple_text_input_protocol_t *con_in; 62714c574f3SArvind Sankar efi_status_t status; 62814c574f3SArvind Sankar 62914c574f3SArvind Sankar con_in = efi_table_attr(efi_system_table, con_in); 63014c574f3SArvind Sankar if (!con_in) 63114c574f3SArvind Sankar return EFI_UNSUPPORTED; 63214c574f3SArvind Sankar efi_set_event_at(events, 0, efi_table_attr(con_in, wait_for_key)); 63314c574f3SArvind Sankar 63414c574f3SArvind Sankar status = efi_bs_call(create_event, EFI_EVT_TIMER, 0, NULL, NULL, &timer); 63514c574f3SArvind Sankar if (status != EFI_SUCCESS) 63614c574f3SArvind Sankar return status; 63714c574f3SArvind Sankar 63814c574f3SArvind Sankar status = efi_bs_call(set_timer, timer, EfiTimerRelative, 63914c574f3SArvind Sankar EFI_100NSEC_PER_USEC * usec); 64014c574f3SArvind Sankar if (status != EFI_SUCCESS) 64114c574f3SArvind Sankar return status; 64214c574f3SArvind Sankar efi_set_event_at(events, 1, timer); 64314c574f3SArvind Sankar 64414c574f3SArvind Sankar status = efi_bs_call(wait_for_event, 2, events, &index); 64514c574f3SArvind Sankar if (status == EFI_SUCCESS) { 64614c574f3SArvind Sankar if (index == 0) 64714c574f3SArvind Sankar status = efi_call_proto(con_in, read_keystroke, key); 64814c574f3SArvind Sankar else 64914c574f3SArvind Sankar status = EFI_TIMEOUT; 65014c574f3SArvind Sankar } 65114c574f3SArvind Sankar 65214c574f3SArvind Sankar efi_bs_call(close_event, timer); 65314c574f3SArvind Sankar 65414c574f3SArvind Sankar return status; 65514c574f3SArvind Sankar } 656ace013a5SArd Biesheuvel 657ace013a5SArd Biesheuvel /** 658ace013a5SArd Biesheuvel * efi_remap_image - Remap a loaded image with the appropriate permissions 659ace013a5SArd Biesheuvel * for code and data 660ace013a5SArd Biesheuvel * 661ace013a5SArd Biesheuvel * @image_base: the base of the image in memory 662ace013a5SArd Biesheuvel * @alloc_size: the size of the area in memory occupied by the image 663ace013a5SArd Biesheuvel * @code_size: the size of the leading part of the image containing code 664ace013a5SArd Biesheuvel * and read-only data 665ace013a5SArd Biesheuvel * 666ace013a5SArd Biesheuvel * efi_remap_image() uses the EFI memory attribute protocol to remap the code 667ace013a5SArd Biesheuvel * region of the loaded image read-only/executable, and the remainder 668ace013a5SArd Biesheuvel * read-write/non-executable. The code region is assumed to start at the base 669ace013a5SArd Biesheuvel * of the image, and will therefore cover the PE/COFF header as well. 670ace013a5SArd Biesheuvel */ 671ace013a5SArd Biesheuvel void efi_remap_image(unsigned long image_base, unsigned alloc_size, 672ace013a5SArd Biesheuvel unsigned long code_size) 673ace013a5SArd Biesheuvel { 674ace013a5SArd Biesheuvel efi_guid_t guid = EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID; 675ace013a5SArd Biesheuvel efi_memory_attribute_protocol_t *memattr; 676ace013a5SArd Biesheuvel efi_status_t status; 677ace013a5SArd Biesheuvel u64 attr; 678ace013a5SArd Biesheuvel 679ace013a5SArd Biesheuvel /* 680ace013a5SArd Biesheuvel * If the firmware implements the EFI_MEMORY_ATTRIBUTE_PROTOCOL, let's 681ace013a5SArd Biesheuvel * invoke it to remap the text/rodata region of the decompressed image 682ace013a5SArd Biesheuvel * as read-only and the data/bss region as non-executable. 683ace013a5SArd Biesheuvel */ 684ace013a5SArd Biesheuvel status = efi_bs_call(locate_protocol, &guid, NULL, (void **)&memattr); 685ace013a5SArd Biesheuvel if (status != EFI_SUCCESS) 686ace013a5SArd Biesheuvel return; 687ace013a5SArd Biesheuvel 688ace013a5SArd Biesheuvel // Get the current attributes for the entire region 689ace013a5SArd Biesheuvel status = memattr->get_memory_attributes(memattr, image_base, 690ace013a5SArd Biesheuvel alloc_size, &attr); 691ace013a5SArd Biesheuvel if (status != EFI_SUCCESS) { 692ace013a5SArd Biesheuvel efi_warn("Failed to retrieve memory attributes for image region: 0x%lx\n", 693ace013a5SArd Biesheuvel status); 694ace013a5SArd Biesheuvel return; 695ace013a5SArd Biesheuvel } 696ace013a5SArd Biesheuvel 697ace013a5SArd Biesheuvel // Mark the code region as read-only 698ace013a5SArd Biesheuvel status = memattr->set_memory_attributes(memattr, image_base, code_size, 699ace013a5SArd Biesheuvel EFI_MEMORY_RO); 700ace013a5SArd Biesheuvel if (status != EFI_SUCCESS) { 701ace013a5SArd Biesheuvel efi_warn("Failed to remap code region read-only\n"); 702ace013a5SArd Biesheuvel return; 703ace013a5SArd Biesheuvel } 704ace013a5SArd Biesheuvel 705ace013a5SArd Biesheuvel // If the entire region was already mapped as non-exec, clear the 706ace013a5SArd Biesheuvel // attribute from the code region. Otherwise, set it on the data 707ace013a5SArd Biesheuvel // region. 708ace013a5SArd Biesheuvel if (attr & EFI_MEMORY_XP) { 709ace013a5SArd Biesheuvel status = memattr->clear_memory_attributes(memattr, image_base, 710ace013a5SArd Biesheuvel code_size, 711ace013a5SArd Biesheuvel EFI_MEMORY_XP); 712ace013a5SArd Biesheuvel if (status != EFI_SUCCESS) 713ace013a5SArd Biesheuvel efi_warn("Failed to remap code region executable\n"); 714ace013a5SArd Biesheuvel } else { 715ace013a5SArd Biesheuvel status = memattr->set_memory_attributes(memattr, 716ace013a5SArd Biesheuvel image_base + code_size, 717ace013a5SArd Biesheuvel alloc_size - code_size, 718ace013a5SArd Biesheuvel EFI_MEMORY_XP); 719ace013a5SArd Biesheuvel if (status != EFI_SUCCESS) 720ace013a5SArd Biesheuvel efi_warn("Failed to remap data region non-executable\n"); 721ace013a5SArd Biesheuvel } 722ace013a5SArd Biesheuvel } 723