1 /* 2 * EFI utils 3 * 4 * Copyright (c) 2017 Rob Clark 5 * 6 * SPDX-License-Identifier: GPL-2.0+ 7 */ 8 9 #include <common.h> 10 #include <charset.h> 11 #include <malloc.h> 12 #include <efi_loader.h> 13 14 static const struct efi_boot_services *bs; 15 static const struct efi_runtime_services *rs; 16 17 #define LOAD_OPTION_ACTIVE 0x00000001 18 #define LOAD_OPTION_FORCE_RECONNECT 0x00000002 19 #define LOAD_OPTION_HIDDEN 0x00000008 20 21 /* 22 * bootmgr implements the logic of trying to find a payload to boot 23 * based on the BootOrder + BootXXXX variables, and then loading it. 24 * 25 * TODO detecting a special key held (f9?) and displaying a boot menu 26 * like you would get on a PC would be clever. 27 * 28 * TODO if we had a way to write and persist variables after the OS 29 * has started, we'd also want to check OsIndications to see if we 30 * should do normal or recovery boot. 31 */ 32 33 34 /* 35 * See section 3.1.3 in the v2.7 UEFI spec for more details on 36 * the layout of EFI_LOAD_OPTION. In short it is: 37 * 38 * typedef struct _EFI_LOAD_OPTION { 39 * UINT32 Attributes; 40 * UINT16 FilePathListLength; 41 * // CHAR16 Description[]; <-- variable length, NULL terminated 42 * // EFI_DEVICE_PATH_PROTOCOL FilePathList[]; <-- FilePathListLength bytes 43 * // UINT8 OptionalData[]; 44 * } EFI_LOAD_OPTION; 45 */ 46 struct load_option { 47 u32 attributes; 48 u16 file_path_length; 49 u16 *label; 50 struct efi_device_path *file_path; 51 u8 *optional_data; 52 }; 53 54 /* parse an EFI_LOAD_OPTION, as described above */ 55 static void parse_load_option(struct load_option *lo, void *ptr) 56 { 57 lo->attributes = *(u32 *)ptr; 58 ptr += sizeof(u32); 59 60 lo->file_path_length = *(u16 *)ptr; 61 ptr += sizeof(u16); 62 63 lo->label = ptr; 64 ptr += (utf16_strlen(lo->label) + 1) * 2; 65 66 lo->file_path = ptr; 67 ptr += lo->file_path_length; 68 69 lo->optional_data = ptr; 70 } 71 72 /* free() the result */ 73 static void *get_var(u16 *name, const efi_guid_t *vendor, 74 unsigned long *size) 75 { 76 efi_guid_t *v = (efi_guid_t *)vendor; 77 efi_status_t ret; 78 void *buf = NULL; 79 80 *size = 0; 81 EFI_CALL(ret = rs->get_variable((s16 *)name, v, NULL, size, buf)); 82 if (ret == EFI_BUFFER_TOO_SMALL) { 83 buf = malloc(*size); 84 EFI_CALL(ret = rs->get_variable((s16 *)name, v, NULL, size, buf)); 85 } 86 87 if (ret != EFI_SUCCESS) { 88 free(buf); 89 *size = 0; 90 return NULL; 91 } 92 93 return buf; 94 } 95 96 /* 97 * Attempt to load load-option number 'n', returning device_path and file_path 98 * if successful. This checks that the EFI_LOAD_OPTION is active (enabled) 99 * and that the specified file to boot exists. 100 */ 101 static void *try_load_entry(uint16_t n, struct efi_device_path **device_path, 102 struct efi_device_path **file_path) 103 { 104 struct load_option lo; 105 u16 varname[] = L"Boot0000"; 106 u16 hexmap[] = L"0123456789ABCDEF"; 107 void *load_option, *image = NULL; 108 unsigned long size; 109 110 varname[4] = hexmap[(n & 0xf000) >> 12]; 111 varname[5] = hexmap[(n & 0x0f00) >> 8]; 112 varname[6] = hexmap[(n & 0x00f0) >> 4]; 113 varname[7] = hexmap[(n & 0x000f) >> 0]; 114 115 load_option = get_var(varname, &efi_global_variable_guid, &size); 116 if (!load_option) 117 return NULL; 118 119 parse_load_option(&lo, load_option); 120 121 if (lo.attributes & LOAD_OPTION_ACTIVE) { 122 efi_status_t ret; 123 u16 *str = NULL; 124 125 debug("%s: trying to load \"%ls\" from: %ls\n", __func__, 126 lo.label, (str = efi_dp_str(lo.file_path))); 127 efi_free_pool(str); 128 129 ret = efi_load_image_from_path(lo.file_path, &image); 130 131 if (ret != EFI_SUCCESS) 132 goto error; 133 134 printf("Booting: %ls\n", lo.label); 135 efi_dp_split_file_path(lo.file_path, device_path, file_path); 136 } 137 138 error: 139 free(load_option); 140 141 return image; 142 } 143 144 /* 145 * Attempt to load, in the order specified by BootOrder EFI variable, the 146 * available load-options, finding and returning the first one that can 147 * be loaded successfully. 148 */ 149 void *efi_bootmgr_load(struct efi_device_path **device_path, 150 struct efi_device_path **file_path) 151 { 152 uint16_t *bootorder; 153 unsigned long size; 154 void *image = NULL; 155 int i, num; 156 157 __efi_entry_check(); 158 159 bs = systab.boottime; 160 rs = systab.runtime; 161 162 bootorder = get_var(L"BootOrder", &efi_global_variable_guid, &size); 163 if (!bootorder) 164 goto error; 165 166 num = size / sizeof(uint16_t); 167 for (i = 0; i < num; i++) { 168 debug("%s: trying to load Boot%04X\n", __func__, bootorder[i]); 169 image = try_load_entry(bootorder[i], device_path, file_path); 170 if (image) 171 break; 172 } 173 174 free(bootorder); 175 176 error: 177 __efi_exit_check(); 178 179 return image; 180 } 181