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