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