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 37 static void efi_panic(EFI_STATUS s, const char *fmt, ...) __dead2 __printflike(2, 3); 38 39 static const boot_module_t *boot_modules[] = 40 { 41 #ifdef EFI_ZFS_BOOT 42 &zfs_module, 43 #endif 44 #ifdef EFI_UFS_BOOT 45 &ufs_module 46 #endif 47 }; 48 49 #define NUM_BOOT_MODULES nitems(boot_modules) 50 51 static EFI_GUID BlockIoProtocolGUID = BLOCK_IO_PROTOCOL; 52 static EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL; 53 static EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL; 54 static EFI_GUID ConsoleControlGUID = EFI_CONSOLE_CONTROL_PROTOCOL_GUID; 55 56 /* 57 * Provide Malloc / Free / Calloc backed by EFIs AllocatePool / FreePool which ensures 58 * memory is correctly aligned avoiding EFI_INVALID_PARAMETER returns from 59 * EFI methods. 60 */ 61 62 void * 63 Malloc(size_t len, const char *file __unused, int line __unused) 64 { 65 void *out; 66 67 if (BS->AllocatePool(EfiLoaderData, len, &out) == EFI_SUCCESS) 68 return (out); 69 70 return (NULL); 71 } 72 73 void 74 Free(void *buf, const char *file __unused, int line __unused) 75 { 76 if (buf != NULL) 77 (void)BS->FreePool(buf); 78 } 79 80 void * 81 Calloc(size_t n1, size_t n2, const char *file, int line) 82 { 83 size_t bytes; 84 void *res; 85 86 bytes = n1 * n2; 87 if ((res = Malloc(bytes, file, line)) != NULL) 88 bzero(res, bytes); 89 90 return (res); 91 } 92 93 /* 94 * load_loader attempts to load the loader image data. 95 * 96 * It tries each module and its respective devices, identified by mod->probe, 97 * in order until a successful load occurs at which point it returns EFI_SUCCESS 98 * and EFI_NOT_FOUND otherwise. 99 * 100 * Only devices which have preferred matching the preferred parameter are tried. 101 */ 102 static EFI_STATUS 103 load_loader(const boot_module_t **modp, dev_info_t **devinfop, void **bufp, 104 size_t *bufsize, int preferred) 105 { 106 UINTN i; 107 dev_info_t *dev; 108 const boot_module_t *mod; 109 110 for (i = 0; i < NUM_BOOT_MODULES; i++) { 111 mod = boot_modules[i]; 112 for (dev = mod->devices(); dev != NULL; dev = dev->next) { 113 if (dev->preferred != preferred) 114 continue; 115 116 if (mod->load(PATH_LOADER_EFI, dev, bufp, bufsize) == 117 EFI_SUCCESS) { 118 *devinfop = dev; 119 *modp = mod; 120 return (EFI_SUCCESS); 121 } 122 } 123 } 124 125 return (EFI_NOT_FOUND); 126 } 127 128 /* 129 * try_boot only returns if it fails to load the loader. If it succeeds 130 * it simply boots, otherwise it returns the status of last EFI call. 131 */ 132 static EFI_STATUS 133 try_boot(void) 134 { 135 size_t bufsize, loadersize, cmdsize; 136 void *buf, *loaderbuf; 137 char *cmd; 138 dev_info_t *dev; 139 const boot_module_t *mod; 140 EFI_HANDLE loaderhandle; 141 EFI_LOADED_IMAGE *loaded_image; 142 EFI_STATUS status; 143 144 status = load_loader(&mod, &dev, &loaderbuf, &loadersize, 1); 145 if (status != EFI_SUCCESS) { 146 status = load_loader(&mod, &dev, &loaderbuf, &loadersize, 0); 147 if (status != EFI_SUCCESS) { 148 printf("Failed to load '%s'\n", PATH_LOADER_EFI); 149 return (status); 150 } 151 } 152 153 /* 154 * Read in and parse the command line from /boot.config or /boot/config, 155 * if present. We'll pass it the next stage via a simple ASCII 156 * string. loader.efi has a hack for ASCII strings, so we'll use that to 157 * keep the size down here. We only try to read the alternate file if 158 * we get EFI_NOT_FOUND because all other errors mean that the boot_module 159 * had troubles with the filesystem. We could return early, but we'll let 160 * loading the actual kernel sort all that out. Since these files are 161 * optional, we don't report errors in trying to read them. 162 */ 163 cmd = NULL; 164 cmdsize = 0; 165 status = mod->load(PATH_DOTCONFIG, dev, &buf, &bufsize); 166 if (status == EFI_NOT_FOUND) 167 status = mod->load(PATH_CONFIG, dev, &buf, &bufsize); 168 if (status == EFI_SUCCESS) { 169 cmdsize = bufsize + 1; 170 cmd = malloc(cmdsize); 171 if (cmd == NULL) 172 goto errout; 173 memcpy(cmd, buf, bufsize); 174 cmd[bufsize] = '\0'; 175 free(buf); 176 buf = NULL; 177 } 178 179 if ((status = BS->LoadImage(TRUE, IH, efi_devpath_last_node(dev->devpath), 180 loaderbuf, loadersize, &loaderhandle)) != EFI_SUCCESS) { 181 printf("Failed to load image provided by %s, size: %zu, (%lu)\n", 182 mod->name, loadersize, EFI_ERROR_CODE(status)); 183 goto errout; 184 } 185 186 if ((status = BS->HandleProtocol(loaderhandle, &LoadedImageGUID, 187 (VOID**)&loaded_image)) != EFI_SUCCESS) { 188 printf("Failed to query LoadedImage provided by %s (%lu)\n", 189 mod->name, EFI_ERROR_CODE(status)); 190 goto errout; 191 } 192 193 if (cmd != NULL) 194 printf(" command args: %s\n", cmd); 195 196 loaded_image->DeviceHandle = dev->devhandle; 197 loaded_image->LoadOptionsSize = cmdsize; 198 loaded_image->LoadOptions = cmd; 199 200 DPRINTF("Starting '%s' in 5 seconds...", PATH_LOADER_EFI); 201 DSTALL(1000000); 202 DPRINTF("."); 203 DSTALL(1000000); 204 DPRINTF("."); 205 DSTALL(1000000); 206 DPRINTF("."); 207 DSTALL(1000000); 208 DPRINTF("."); 209 DSTALL(1000000); 210 DPRINTF(".\n"); 211 212 if ((status = BS->StartImage(loaderhandle, NULL, NULL)) != 213 EFI_SUCCESS) { 214 printf("Failed to start image provided by %s (%lu)\n", 215 mod->name, EFI_ERROR_CODE(status)); 216 loaded_image->LoadOptionsSize = 0; 217 loaded_image->LoadOptions = NULL; 218 } 219 220 errout: 221 if (cmd != NULL) 222 free(cmd); 223 if (buf != NULL) 224 free(buf); 225 if (loaderbuf != NULL) 226 free(loaderbuf); 227 228 return (status); 229 } 230 231 /* 232 * probe_handle determines if the passed handle represents a logical partition 233 * if it does it uses each module in order to probe it and if successful it 234 * returns 0. 235 */ 236 static int 237 probe_handle(EFI_HANDLE h, EFI_DEVICE_PATH *imgpath) 238 { 239 dev_info_t *devinfo; 240 EFI_BLOCK_IO *blkio; 241 EFI_DEVICE_PATH *devpath; 242 EFI_STATUS status; 243 UINTN i; 244 int preferred; 245 246 /* Figure out if we're dealing with an actual partition. */ 247 status = BS->HandleProtocol(h, &DevicePathGUID, (void **)&devpath); 248 if (status == EFI_UNSUPPORTED) 249 return (0); 250 251 if (status != EFI_SUCCESS) { 252 DPRINTF("\nFailed to query DevicePath (%lu)\n", 253 EFI_ERROR_CODE(status)); 254 return (-1); 255 } 256 #ifdef EFI_DEBUG 257 { 258 CHAR16 *text = efi_devpath_name(devpath); 259 DPRINTF("probing: %S ", text); 260 efi_free_devpath_name(text); 261 } 262 #endif 263 status = BS->HandleProtocol(h, &BlockIoProtocolGUID, (void **)&blkio); 264 if (status == EFI_UNSUPPORTED) 265 return (0); 266 267 if (status != EFI_SUCCESS) { 268 DPRINTF("\nFailed to query BlockIoProtocol (%lu)\n", 269 EFI_ERROR_CODE(status)); 270 return (-1); 271 } 272 273 if (!blkio->Media->LogicalPartition) 274 return (0); 275 276 preferred = efi_devpath_same_disk(imgpath, devpath); 277 278 /* Run through each module, see if it can load this partition */ 279 devinfo = malloc(sizeof(*devinfo)); 280 if (devinfo == NULL) { 281 DPRINTF("\nFailed to allocate devinfo\n"); 282 return (-1); 283 } 284 devinfo->dev = blkio; 285 devinfo->devpath = devpath; 286 devinfo->devhandle = h; 287 devinfo->preferred = preferred; 288 devinfo->next = NULL; 289 290 for (i = 0; i < NUM_BOOT_MODULES; i++) { 291 devinfo->devdata = NULL; 292 293 status = boot_modules[i]->probe(devinfo); 294 if (status == EFI_SUCCESS) 295 return (preferred + 1); 296 } 297 free(devinfo); 298 299 return (0); 300 } 301 302 const char *prio_str[] = { 303 "error", 304 "not supported", 305 "good", 306 "better" 307 }; 308 309 EFI_STATUS 310 efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE *Xsystab) 311 { 312 EFI_HANDLE *handles; 313 EFI_LOADED_IMAGE *img; 314 EFI_DEVICE_PATH *imgpath; 315 EFI_STATUS status; 316 EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl = NULL; 317 SIMPLE_TEXT_OUTPUT_INTERFACE *conout = NULL; 318 UINTN i, hsize, nhandles; 319 CHAR16 *text; 320 UINT16 boot_current; 321 size_t sz; 322 UINT16 boot_order[100]; 323 int rv; 324 325 /* Basic initialization*/ 326 ST = Xsystab; 327 IH = Ximage; 328 BS = ST->BootServices; 329 RS = ST->RuntimeServices; 330 331 /* Set up the console, so printf works. */ 332 status = BS->LocateProtocol(&ConsoleControlGUID, NULL, 333 (VOID **)&ConsoleControl); 334 if (status == EFI_SUCCESS) 335 (void)ConsoleControl->SetMode(ConsoleControl, 336 EfiConsoleControlScreenText); 337 /* 338 * Reset the console enable the cursor. Later we'll choose a better 339 * console size through GOP/UGA. 340 */ 341 conout = ST->ConOut; 342 conout->Reset(conout, TRUE); 343 /* Explicitly set conout to mode 0, 80x25 */ 344 conout->SetMode(conout, 0); 345 conout->EnableCursor(conout, TRUE); 346 conout->ClearScreen(conout); 347 348 printf("\n>> FreeBSD EFI boot block\n"); 349 printf(" Loader path: %s\n\n", PATH_LOADER_EFI); 350 printf(" Initializing modules:"); 351 for (i = 0; i < NUM_BOOT_MODULES; i++) { 352 printf(" %s", boot_modules[i]->name); 353 if (boot_modules[i]->init != NULL) 354 boot_modules[i]->init(); 355 } 356 putchar('\n'); 357 358 /* Determine the devpath of our image so we can prefer it. */ 359 status = BS->HandleProtocol(IH, &LoadedImageGUID, (VOID**)&img); 360 imgpath = NULL; 361 if (status == EFI_SUCCESS) { 362 text = efi_devpath_name(img->FilePath); 363 if (text != NULL) { 364 printf(" Load Path: %S\n", text); 365 efi_setenv_freebsd_wcs("Boot1Path", text); 366 efi_free_devpath_name(text); 367 } 368 369 status = BS->HandleProtocol(img->DeviceHandle, &DevicePathGUID, 370 (void **)&imgpath); 371 if (status != EFI_SUCCESS) { 372 DPRINTF("Failed to get image DevicePath (%lu)\n", 373 EFI_ERROR_CODE(status)); 374 } else { 375 text = efi_devpath_name(imgpath); 376 if (text != NULL) { 377 printf(" Load Device: %S\n", text); 378 efi_setenv_freebsd_wcs("Boot1Dev", text); 379 efi_free_devpath_name(text); 380 } 381 } 382 } 383 384 boot_current = 0; 385 sz = sizeof(boot_current); 386 if (efi_global_getenv("BootCurrent", &boot_current, &sz) == EFI_SUCCESS) { 387 printf(" BootCurrent: %04x\n", boot_current); 388 389 sz = sizeof(boot_order); 390 if (efi_global_getenv("BootOrder", &boot_order, &sz) == EFI_SUCCESS) { 391 printf(" BootOrder:"); 392 for (i = 0; i < sz / sizeof(boot_order[0]); i++) 393 printf(" %04x%s", boot_order[i], 394 boot_order[i] == boot_current ? "[*]" : ""); 395 printf("\n"); 396 } 397 } 398 399 #ifdef TEST_FAILURE 400 /* 401 * For testing failover scenarios, it's nice to be able to fail fast. 402 * Define TEST_FAILURE to create a boot1.efi that always fails after 403 * reporting the boot manager protocol details. 404 */ 405 BS->Exit(IH, EFI_OUT_OF_RESOURCES, 0, NULL); 406 #endif 407 408 hsize = 0; 409 BS->LocateHandle(ByProtocol, &BlockIoProtocolGUID, NULL, 410 &hsize, NULL); 411 handles = malloc(hsize); 412 if (handles == NULL) 413 efi_panic(EFI_OUT_OF_RESOURCES, "Failed to allocate %d handles\n", 414 hsize); 415 status = BS->LocateHandle(ByProtocol, &BlockIoProtocolGUID, 416 NULL, &hsize, handles); 417 if (status != EFI_SUCCESS) 418 efi_panic(status, "Failed to get device handles\n"); 419 420 /* Scan all partitions, probing with all modules. */ 421 nhandles = hsize / sizeof(*handles); 422 printf(" Probing %zu block devices...", nhandles); 423 DPRINTF("\n"); 424 425 for (i = 0; i < nhandles; i++) { 426 rv = probe_handle(handles[i], imgpath); 427 #ifdef EFI_DEBUG 428 printf("%c", "x.+*"[rv + 1]); 429 #else 430 printf("%s\n", prio_str[rv + 1]); 431 #endif 432 } 433 printf(" done\n"); 434 435 /* Status summary. */ 436 for (i = 0; i < NUM_BOOT_MODULES; i++) { 437 printf(" "); 438 boot_modules[i]->status(); 439 } 440 441 try_boot(); 442 443 /* If we get here, we're out of luck... */ 444 efi_panic(EFI_LOAD_ERROR, "No bootable partitions found!"); 445 } 446 447 /* 448 * add_device adds a device to the passed devinfo list. 449 */ 450 void 451 add_device(dev_info_t **devinfop, dev_info_t *devinfo) 452 { 453 dev_info_t *dev; 454 455 if (*devinfop == NULL) { 456 *devinfop = devinfo; 457 return; 458 } 459 460 for (dev = *devinfop; dev->next != NULL; dev = dev->next) 461 ; 462 463 dev->next = devinfo; 464 } 465 466 /* 467 * OK. We totally give up. Exit back to EFI with a sensible status so 468 * it can try the next option on the list. 469 */ 470 static void 471 efi_panic(EFI_STATUS s, const char *fmt, ...) 472 { 473 va_list ap; 474 475 printf("panic: "); 476 va_start(ap, fmt); 477 vprintf(fmt, ap); 478 va_end(ap); 479 printf("\n"); 480 481 BS->Exit(IH, s, 0, NULL); 482 } 483 484 void 485 putchar(int c) 486 { 487 CHAR16 buf[2]; 488 489 if (c == '\n') { 490 buf[0] = '\r'; 491 buf[1] = 0; 492 ST->ConOut->OutputString(ST->ConOut, buf); 493 } 494 buf[0] = c; 495 buf[1] = 0; 496 ST->ConOut->OutputString(ST->ConOut, buf); 497 } 498