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