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 124 debug("%s: trying to load \"%ls\" from %pD\n", 125 __func__, lo.label, lo.file_path); 126 127 ret = efi_load_image_from_path(lo.file_path, &image); 128 129 if (ret != EFI_SUCCESS) 130 goto error; 131 132 printf("Booting: %ls\n", lo.label); 133 efi_dp_split_file_path(lo.file_path, device_path, file_path); 134 } 135 136 error: 137 free(load_option); 138 139 return image; 140 } 141 142 /* 143 * Attempt to load, in the order specified by BootOrder EFI variable, the 144 * available load-options, finding and returning the first one that can 145 * be loaded successfully. 146 */ 147 void *efi_bootmgr_load(struct efi_device_path **device_path, 148 struct efi_device_path **file_path) 149 { 150 uint16_t *bootorder; 151 unsigned long size; 152 void *image = NULL; 153 int i, num; 154 155 __efi_entry_check(); 156 157 bs = systab.boottime; 158 rs = systab.runtime; 159 160 bootorder = get_var(L"BootOrder", &efi_global_variable_guid, &size); 161 if (!bootorder) 162 goto error; 163 164 num = size / sizeof(uint16_t); 165 for (i = 0; i < num; i++) { 166 debug("%s: trying to load Boot%04X\n", __func__, bootorder[i]); 167 image = try_load_entry(bootorder[i], device_path, file_path); 168 if (image) 169 break; 170 } 171 172 free(bootorder); 173 174 error: 175 __efi_exit_check(); 176 177 return image; 178 } 179