1*f412fd2aSLoGin #include "efidef.h" 2*f412fd2aSLoGin #include <efi.h> 3*f412fd2aSLoGin #include <efilib.h> 4*f412fd2aSLoGin #include <lib.h> 5*f412fd2aSLoGin #include <dragonstub/dragonstub.h> 6*f412fd2aSLoGin 7*f412fd2aSLoGin enum efistub_event { 8*f412fd2aSLoGin EFISTUB_EVT_INITRD, 9*f412fd2aSLoGin EFISTUB_EVT_LOAD_OPTIONS, 10*f412fd2aSLoGin EFISTUB_EVT_COUNT, 11*f412fd2aSLoGin }; 12*f412fd2aSLoGin 13*f412fd2aSLoGin #define STR_WITH_SIZE(s) sizeof(s), s 14*f412fd2aSLoGin 15*f412fd2aSLoGin static const struct { 16*f412fd2aSLoGin u32 pcr_index; 17*f412fd2aSLoGin u32 event_id; 18*f412fd2aSLoGin u32 event_data_len; 19*f412fd2aSLoGin u8 event_data[52]; 20*f412fd2aSLoGin } events[] = { 21*f412fd2aSLoGin [EFISTUB_EVT_INITRD] = { 9, INITRD_EVENT_TAG_ID, 22*f412fd2aSLoGin STR_WITH_SIZE("Linux initrd") }, 23*f412fd2aSLoGin [EFISTUB_EVT_LOAD_OPTIONS] = { 9, LOAD_OPTIONS_EVENT_TAG_ID, 24*f412fd2aSLoGin STR_WITH_SIZE( 25*f412fd2aSLoGin "LOADED_IMAGE::LoadOptions") }, 26*f412fd2aSLoGin }; 27*f412fd2aSLoGin 28*f412fd2aSLoGin static efi_status_t efi_measure_tagged_event(unsigned long load_addr, 29*f412fd2aSLoGin unsigned long load_size, 30*f412fd2aSLoGin enum efistub_event event) 31*f412fd2aSLoGin { 32*f412fd2aSLoGin efi_guid_t tcg2_guid = EFI_TCG2_PROTOCOL_GUID; 33*f412fd2aSLoGin efi_tcg2_protocol_t *tcg2 = NULL; 34*f412fd2aSLoGin efi_status_t status; 35*f412fd2aSLoGin 36*f412fd2aSLoGin efi_bs_call(LocateProtocol, &tcg2_guid, NULL, (void **)&tcg2); 37*f412fd2aSLoGin if (tcg2) { 38*f412fd2aSLoGin struct efi_measured_event { 39*f412fd2aSLoGin efi_tcg2_event_t event_data; 40*f412fd2aSLoGin efi_tcg2_tagged_event_t tagged_event; 41*f412fd2aSLoGin u8 tagged_event_data[]; 42*f412fd2aSLoGin } * evt; 43*f412fd2aSLoGin int size = sizeof(*evt) + events[event].event_data_len; 44*f412fd2aSLoGin 45*f412fd2aSLoGin status = efi_bs_call(AllocatePool, EfiLoaderData, size, 46*f412fd2aSLoGin (void **)&evt); 47*f412fd2aSLoGin if (status != EFI_SUCCESS) 48*f412fd2aSLoGin goto fail; 49*f412fd2aSLoGin 50*f412fd2aSLoGin evt->event_data = (struct efi_tcg2_event){ 51*f412fd2aSLoGin .event_size = size, 52*f412fd2aSLoGin .event_header.header_size = 53*f412fd2aSLoGin sizeof(evt->event_data.event_header), 54*f412fd2aSLoGin .event_header.header_version = 55*f412fd2aSLoGin EFI_TCG2_EVENT_HEADER_VERSION, 56*f412fd2aSLoGin .event_header.pcr_index = events[event].pcr_index, 57*f412fd2aSLoGin .event_header.event_type = EV_EVENT_TAG, 58*f412fd2aSLoGin }; 59*f412fd2aSLoGin 60*f412fd2aSLoGin evt->tagged_event = (struct efi_tcg2_tagged_event){ 61*f412fd2aSLoGin .tagged_event_id = events[event].event_id, 62*f412fd2aSLoGin .tagged_event_data_size = events[event].event_data_len, 63*f412fd2aSLoGin }; 64*f412fd2aSLoGin 65*f412fd2aSLoGin memcpy(evt->tagged_event_data, events[event].event_data, 66*f412fd2aSLoGin events[event].event_data_len); 67*f412fd2aSLoGin 68*f412fd2aSLoGin status = efi_call_proto(tcg2, hash_log_extend_event, 0, 69*f412fd2aSLoGin load_addr, load_size, &evt->event_data); 70*f412fd2aSLoGin efi_bs_call(FreePool, evt); 71*f412fd2aSLoGin 72*f412fd2aSLoGin if (status != EFI_SUCCESS) 73*f412fd2aSLoGin goto fail; 74*f412fd2aSLoGin return EFI_SUCCESS; 75*f412fd2aSLoGin } 76*f412fd2aSLoGin 77*f412fd2aSLoGin return EFI_UNSUPPORTED; 78*f412fd2aSLoGin fail: 79*f412fd2aSLoGin efi_warn("Failed to measure data for event %d: 0x%lx\n", event, status); 80*f412fd2aSLoGin return status; 81*f412fd2aSLoGin } 82*f412fd2aSLoGin 83*f412fd2aSLoGin /* 84*f412fd2aSLoGin * At least some versions of Dell firmware pass the entire contents of the 85*f412fd2aSLoGin * Boot#### variable, i.e. the EFI_LOAD_OPTION descriptor, rather than just the 86*f412fd2aSLoGin * OptionalData field. 87*f412fd2aSLoGin * 88*f412fd2aSLoGin * Detect this case and extract OptionalData. 89*f412fd2aSLoGin */ 90*f412fd2aSLoGin void efi_apply_loadoptions_quirk(const void **load_options, 91*f412fd2aSLoGin u32 *load_options_size) 92*f412fd2aSLoGin { 93*f412fd2aSLoGin #ifndef CONFIG_X86 94*f412fd2aSLoGin return; 95*f412fd2aSLoGin #else 96*f412fd2aSLoGin const efi_load_option_t *load_option = *load_options; 97*f412fd2aSLoGin efi_load_option_unpacked_t load_option_unpacked; 98*f412fd2aSLoGin if (!load_option) 99*f412fd2aSLoGin return; 100*f412fd2aSLoGin if (*load_options_size < sizeof(*load_option)) 101*f412fd2aSLoGin return; 102*f412fd2aSLoGin if ((load_option->attributes & ~EFI_LOAD_OPTION_BOOT_MASK) != 0) 103*f412fd2aSLoGin return; 104*f412fd2aSLoGin 105*f412fd2aSLoGin if (!efi_load_option_unpack(&load_option_unpacked, load_option, 106*f412fd2aSLoGin *load_options_size)) 107*f412fd2aSLoGin return; 108*f412fd2aSLoGin 109*f412fd2aSLoGin efi_warn_once(FW_BUG "LoadOptions is an EFI_LOAD_OPTION descriptor\n"); 110*f412fd2aSLoGin efi_warn_once(FW_BUG "Using OptionalData as a workaround\n"); 111*f412fd2aSLoGin 112*f412fd2aSLoGin *load_options = load_option_unpacked.optional_data; 113*f412fd2aSLoGin *load_options_size = load_option_unpacked.optional_data_size; 114*f412fd2aSLoGin #endif 115*f412fd2aSLoGin } 116*f412fd2aSLoGin 117*f412fd2aSLoGin /* 118*f412fd2aSLoGin * Convert the unicode UEFI command line to ASCII to pass to kernel. 119*f412fd2aSLoGin * Size of memory allocated return in *cmd_line_len. 120*f412fd2aSLoGin * Returns NULL on error. 121*f412fd2aSLoGin */ 122*f412fd2aSLoGin char *efi_convert_cmdline(EFI_LOADED_IMAGE *image, int *cmd_line_len) 123*f412fd2aSLoGin { 124*f412fd2aSLoGin const efi_char16_t *options = efi_table_attr(image, LoadOptions); 125*f412fd2aSLoGin u32 options_size = efi_table_attr(image, LoadOptionsSize); 126*f412fd2aSLoGin int options_bytes = 0, safe_options_bytes = 0; /* UTF-8 bytes */ 127*f412fd2aSLoGin unsigned long cmdline_addr = 0; 128*f412fd2aSLoGin const efi_char16_t *s2; 129*f412fd2aSLoGin bool in_quote = false; 130*f412fd2aSLoGin efi_status_t status; 131*f412fd2aSLoGin u32 options_chars; 132*f412fd2aSLoGin 133*f412fd2aSLoGin if (options_size > 0) 134*f412fd2aSLoGin efi_measure_tagged_event((unsigned long)options, options_size, 135*f412fd2aSLoGin EFISTUB_EVT_LOAD_OPTIONS); 136*f412fd2aSLoGin 137*f412fd2aSLoGin efi_apply_loadoptions_quirk((const void **)&options, &options_size); 138*f412fd2aSLoGin options_chars = options_size / sizeof(efi_char16_t); 139*f412fd2aSLoGin 140*f412fd2aSLoGin if (options) { 141*f412fd2aSLoGin s2 = options; 142*f412fd2aSLoGin while (options_bytes < COMMAND_LINE_SIZE && options_chars--) { 143*f412fd2aSLoGin efi_char16_t c = *s2++; 144*f412fd2aSLoGin 145*f412fd2aSLoGin if (c < 0x80) { 146*f412fd2aSLoGin if (c == L'\0' || c == L'\n') 147*f412fd2aSLoGin break; 148*f412fd2aSLoGin if (c == L'"') 149*f412fd2aSLoGin in_quote = !in_quote; 150*f412fd2aSLoGin else if (!in_quote && isspace((char)c)) 151*f412fd2aSLoGin safe_options_bytes = options_bytes; 152*f412fd2aSLoGin 153*f412fd2aSLoGin options_bytes++; 154*f412fd2aSLoGin continue; 155*f412fd2aSLoGin } 156*f412fd2aSLoGin 157*f412fd2aSLoGin /* 158*f412fd2aSLoGin * Get the number of UTF-8 bytes corresponding to a 159*f412fd2aSLoGin * UTF-16 character. 160*f412fd2aSLoGin * The first part handles everything in the BMP. 161*f412fd2aSLoGin */ 162*f412fd2aSLoGin options_bytes += 2 + (c >= 0x800); 163*f412fd2aSLoGin /* 164*f412fd2aSLoGin * Add one more byte for valid surrogate pairs. Invalid 165*f412fd2aSLoGin * surrogates will be replaced with 0xfffd and take up 166*f412fd2aSLoGin * only 3 bytes. 167*f412fd2aSLoGin */ 168*f412fd2aSLoGin if ((c & 0xfc00) == 0xd800) { 169*f412fd2aSLoGin /* 170*f412fd2aSLoGin * If the very last word is a high surrogate, 171*f412fd2aSLoGin * we must ignore it since we can't access the 172*f412fd2aSLoGin * low surrogate. 173*f412fd2aSLoGin */ 174*f412fd2aSLoGin if (!options_chars) { 175*f412fd2aSLoGin options_bytes -= 3; 176*f412fd2aSLoGin } else if ((*s2 & 0xfc00) == 0xdc00) { 177*f412fd2aSLoGin options_bytes++; 178*f412fd2aSLoGin options_chars--; 179*f412fd2aSLoGin s2++; 180*f412fd2aSLoGin } 181*f412fd2aSLoGin } 182*f412fd2aSLoGin } 183*f412fd2aSLoGin if (options_bytes >= COMMAND_LINE_SIZE) { 184*f412fd2aSLoGin options_bytes = safe_options_bytes; 185*f412fd2aSLoGin efi_err("Command line is too long: truncated to %d bytes\n", 186*f412fd2aSLoGin options_bytes); 187*f412fd2aSLoGin } 188*f412fd2aSLoGin } 189*f412fd2aSLoGin 190*f412fd2aSLoGin options_bytes++; /* NUL termination */ 191*f412fd2aSLoGin 192*f412fd2aSLoGin status = efi_bs_call(AllocatePool, EfiLoaderData, options_bytes, 193*f412fd2aSLoGin (void **)&cmdline_addr); 194*f412fd2aSLoGin if (status != EFI_SUCCESS) 195*f412fd2aSLoGin return NULL; 196*f412fd2aSLoGin 197*f412fd2aSLoGin snprintf((char *)cmdline_addr, options_bytes, "%.*ls", 198*f412fd2aSLoGin options_bytes - 1, options); 199*f412fd2aSLoGin 200*f412fd2aSLoGin *cmd_line_len = options_bytes; 201*f412fd2aSLoGin return (char *)cmdline_addr; 202*f412fd2aSLoGin } 203