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