1 /*- 2 * Copyright (c) 1998 Robert Nordier 3 * All rights reserved. 4 * Copyright (c) 2001 Robert Drehmel 5 * All rights reserved. 6 * Copyright (c) 2014 Nathan Whitehorn 7 * All rights reserved. 8 * Copyright (c) 2015 Eric McCorkle 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms are freely 12 * permitted provided that the above copyright notice and this 13 * paragraph and the following disclaimer are duplicated in all 14 * such forms. 15 * 16 * This software is provided "AS IS" and without any express or 17 * implied warranties, including, without limitation, the implied 18 * warranties of merchantability and fitness for a particular 19 * purpose. 20 */ 21 22 #include <sys/cdefs.h> 23 __FBSDID("$FreeBSD$"); 24 25 #include <sys/param.h> 26 #include <machine/elf.h> 27 #include <machine/stdarg.h> 28 #include <stand.h> 29 30 #include <efi.h> 31 #include <eficonsctl.h> 32 #include <efichar.h> 33 34 #include "boot_module.h" 35 #include "paths.h" 36 #include "proto.h" 37 38 static EFI_GUID BlockIoProtocolGUID = BLOCK_IO_PROTOCOL; 39 static EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL; 40 41 #ifndef EFI_DEBUG 42 static const char *prio_str[] = { 43 "error", 44 "not supported", 45 "good", 46 "better" 47 }; 48 #endif 49 50 /* 51 * probe_handle determines if the passed handle represents a logical partition 52 * if it does it uses each module in order to probe it and if successful it 53 * returns EFI_SUCCESS. 54 */ 55 static int 56 probe_handle(EFI_HANDLE h, EFI_DEVICE_PATH *imgpath) 57 { 58 dev_info_t *devinfo; 59 EFI_BLOCK_IO *blkio; 60 EFI_DEVICE_PATH *devpath; 61 EFI_STATUS status; 62 UINTN i; 63 int preferred; 64 65 /* Figure out if we're dealing with an actual partition. */ 66 status = OpenProtocolByHandle(h, &DevicePathGUID, (void **)&devpath); 67 if (status == EFI_UNSUPPORTED) 68 return (0); 69 70 if (status != EFI_SUCCESS) { 71 DPRINTF("\nFailed to query DevicePath (%lu)\n", 72 EFI_ERROR_CODE(status)); 73 return (-1); 74 } 75 #ifdef EFI_DEBUG 76 { 77 CHAR16 *text = efi_devpath_name(devpath); 78 DPRINTF("probing: %S ", text); 79 efi_free_devpath_name(text); 80 } 81 #endif 82 status = OpenProtocolByHandle(h, &BlockIoProtocolGUID, (void **)&blkio); 83 if (status == EFI_UNSUPPORTED) 84 return (0); 85 86 if (status != EFI_SUCCESS) { 87 DPRINTF("\nFailed to query BlockIoProtocol (%lu)\n", 88 EFI_ERROR_CODE(status)); 89 return (-1); 90 } 91 92 if (!blkio->Media->LogicalPartition) 93 return (0); 94 95 preferred = efi_devpath_same_disk(imgpath, devpath); 96 97 /* Run through each module, see if it can load this partition */ 98 devinfo = malloc(sizeof(*devinfo)); 99 if (devinfo == NULL) { 100 DPRINTF("\nFailed to allocate devinfo\n"); 101 return (-1); 102 } 103 devinfo->dev = blkio; 104 devinfo->devpath = devpath; 105 devinfo->devhandle = h; 106 devinfo->preferred = preferred; 107 devinfo->next = NULL; 108 109 for (i = 0; i < num_boot_modules; i++) { 110 devinfo->devdata = NULL; 111 112 status = boot_modules[i]->probe(devinfo); 113 if (status == EFI_SUCCESS) 114 return (preferred + 1); 115 } 116 free(devinfo); 117 118 return (0); 119 } 120 121 /* 122 * load_loader attempts to load the loader image data. 123 * 124 * It tries each module and its respective devices, identified by mod->probe, 125 * in order until a successful load occurs at which point it returns EFI_SUCCESS 126 * and EFI_NOT_FOUND otherwise. 127 * 128 * Only devices which have preferred matching the preferred parameter are tried. 129 */ 130 static EFI_STATUS 131 load_loader(const boot_module_t **modp, dev_info_t **devinfop, void **bufp, 132 size_t *bufsize, int preferred) 133 { 134 UINTN i; 135 dev_info_t *dev; 136 const boot_module_t *mod; 137 138 for (i = 0; i < num_boot_modules; i++) { 139 mod = boot_modules[i]; 140 for (dev = mod->devices(); dev != NULL; dev = dev->next) { 141 if (dev->preferred != preferred) 142 continue; 143 144 if (mod->load(PATH_LOADER_EFI, dev, bufp, bufsize) == 145 EFI_SUCCESS) { 146 *devinfop = dev; 147 *modp = mod; 148 return (EFI_SUCCESS); 149 } 150 } 151 } 152 153 return (EFI_NOT_FOUND); 154 } 155 156 void 157 choice_protocol(EFI_HANDLE *handles, UINTN nhandles, EFI_DEVICE_PATH *imgpath) 158 { 159 UINT16 boot_current; 160 size_t sz; 161 UINT16 boot_order[100]; 162 unsigned i; 163 int rv; 164 EFI_STATUS status; 165 const boot_module_t *mod; 166 dev_info_t *dev; 167 void *loaderbuf; 168 size_t loadersize; 169 170 /* Report UEFI Boot Manager Protocol details */ 171 boot_current = 0; 172 sz = sizeof(boot_current); 173 if (efi_global_getenv("BootCurrent", &boot_current, &sz) == EFI_SUCCESS) { 174 printf(" BootCurrent: %04x\n", boot_current); 175 176 sz = sizeof(boot_order); 177 if (efi_global_getenv("BootOrder", &boot_order, &sz) == EFI_SUCCESS) { 178 printf(" BootOrder:"); 179 for (i = 0; i < sz / sizeof(boot_order[0]); i++) 180 printf(" %04x%s", boot_order[i], 181 boot_order[i] == boot_current ? "[*]" : ""); 182 printf("\n"); 183 } 184 } 185 186 #ifdef TEST_FAILURE 187 /* 188 * For testing failover scenarios, it's nice to be able to fail fast. 189 * Define TEST_FAILURE to create a boot1.efi that always fails after 190 * reporting the boot manager protocol details. 191 */ 192 BS->Exit(IH, EFI_OUT_OF_RESOURCES, 0, NULL); 193 #endif 194 195 /* Scan all partitions, probing with all modules. */ 196 printf(" Probing %zu block devices...", nhandles); 197 DPRINTF("\n"); 198 for (i = 0; i < nhandles; i++) { 199 rv = probe_handle(handles[i], imgpath); 200 #ifdef EFI_DEBUG 201 printf("%c", "x.+*"[rv + 1]); 202 #else 203 printf("%s\n", prio_str[rv + 1]); 204 #endif 205 } 206 printf(" done\n"); 207 208 209 /* Status summary. */ 210 for (i = 0; i < num_boot_modules; i++) { 211 printf(" "); 212 boot_modules[i]->status(); 213 } 214 215 status = load_loader(&mod, &dev, &loaderbuf, &loadersize, 1); 216 if (status != EFI_SUCCESS) { 217 status = load_loader(&mod, &dev, &loaderbuf, &loadersize, 0); 218 if (status != EFI_SUCCESS) { 219 printf("Failed to load '%s'\n", PATH_LOADER_EFI); 220 return; 221 } 222 } 223 224 try_boot(mod, dev, loaderbuf, loadersize); 225 } 226