boot1.c revision 294768
1118611Snjl/*- 2118611Snjl * Copyright (c) 1998 Robert Nordier 3118611Snjl * All rights reserved. 4118611Snjl * Copyright (c) 2001 Robert Drehmel 5118611Snjl * All rights reserved. 6118611Snjl * Copyright (c) 2014 Nathan Whitehorn 7217365Sjkim * All rights reserved. 8229989Sjkim * Copyright (c) 2015 Eric McCorkle 9118611Snjl * All rights reserved. 10118611Snjl * 11217365Sjkim * Redistribution and use in source and binary forms are freely 12217365Sjkim * permitted provided that the above copyright notice and this 13217365Sjkim * paragraph and the following disclaimer are duplicated in all 14217365Sjkim * such forms. 15217365Sjkim * 16217365Sjkim * This software is provided "AS IS" and without any express or 17217365Sjkim * implied warranties, including, without limitation, the implied 18217365Sjkim * warranties of merchantability and fitness for a particular 19217365Sjkim * purpose. 20217365Sjkim */ 21217365Sjkim 22217365Sjkim#include <sys/cdefs.h> 23217365Sjkim__FBSDID("$FreeBSD: head/sys/boot/efi/boot1/boot1.c 294768 2016-01-26 06:26:55Z imp $"); 24217365Sjkim 25118611Snjl#include <sys/param.h> 26217365Sjkim#include <machine/elf.h> 27217365Sjkim#include <machine/stdarg.h> 28217365Sjkim#include <stand.h> 29118611Snjl 30217365Sjkim#include <efi.h> 31217365Sjkim#include <eficonsctl.h> 32217365Sjkim 33217365Sjkim#include "boot_module.h" 34217365Sjkim#include "paths.h" 35217365Sjkim 36217365Sjkimstatic const boot_module_t *boot_modules[] = 37217365Sjkim{ 38217365Sjkim#ifdef EFI_ZFS_BOOT 39217365Sjkim &zfs_module, 40217365Sjkim#endif 41217365Sjkim#ifdef EFI_UFS_BOOT 42217365Sjkim &ufs_module 43118611Snjl#endif 44118611Snjl}; 45118611Snjl 46118611Snjl#define NUM_BOOT_MODULES (sizeof(boot_modules) / sizeof(boot_module_t*)) 47151937Sjkim/* The initial number of handles used to query EFI for partitions. */ 48193529Sjkim#define NUM_HANDLES_INIT 24 49210976Sjkim 50240716Sjkimvoid putchar(int c); 51118611SnjlEFI_STATUS efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE* Xsystab); 52118611Snjl 53118611Snjlstatic void try_load(const boot_module_t* mod); 54118611Snjlstatic EFI_STATUS probe_handle(EFI_HANDLE h); 55118611Snjl 56118611SnjlEFI_SYSTEM_TABLE *systab; 57118611SnjlEFI_BOOT_SERVICES *bs; 58118611Snjlstatic EFI_HANDLE *image; 59151937Sjkim 60118611Snjlstatic EFI_GUID BlockIoProtocolGUID = BLOCK_IO_PROTOCOL; 61151937Sjkimstatic EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL; 62151937Sjkimstatic EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL; 63151937Sjkimstatic EFI_GUID ConsoleControlGUID = EFI_CONSOLE_CONTROL_PROTOCOL_GUID; 64151937Sjkim 65151937Sjkim/* 66237412Sjkim * Provide Malloc / Free backed by EFIs AllocatePool / FreePool which ensures 67151937Sjkim * memory is correctly aligned avoiding EFI_INVALID_PARAMETER returns from 68151937Sjkim * EFI methods. 69151937Sjkim */ 70151937Sjkimvoid * 71151937SjkimMalloc(size_t len, const char *file __unused, int line __unused) 72151937Sjkim{ 73240716Sjkim void *out; 74240716Sjkim 75240716Sjkim if (bs->AllocatePool(EfiLoaderData, len, &out) == EFI_SUCCESS) 76240716Sjkim return (out); 77151937Sjkim 78151937Sjkim return (NULL); 79151937Sjkim} 80151937Sjkim 81193529Sjkimvoid 82151937SjkimFree(void *buf, const char *file __unused, int line __unused) 83151937Sjkim{ 84151937Sjkim (void)bs->FreePool(buf); 85151937Sjkim} 86197104Sjkim 87197104Sjkim/* 88197104Sjkim * This function only returns if it fails to load the kernel. If it 89197104Sjkim * succeeds, it simply boots the kernel. 90197104Sjkim */ 91151937Sjkimvoid 92197104Sjkimtry_load(const boot_module_t *mod) 93197104Sjkim{ 94197104Sjkim size_t bufsize, cmdsize; 95197104Sjkim void *buf; 96197104Sjkim char *cmd; 97197104Sjkim dev_info_t *dev; 98197104Sjkim EFI_HANDLE loaderhandle; 99197104Sjkim EFI_LOADED_IMAGE *loaded_image; 100197104Sjkim EFI_STATUS status; 101197104Sjkim 102197104Sjkim /* 103240716Sjkim * Read in and parse the command line from /boot.config or /boot/config, 104197104Sjkim * if present. We'll pass it the next stage via a simple ASCII 105197104Sjkim * string. loader.efi has a hack for ASCII strings, so we'll use that to 106118611Snjl * keep the size down here. We only try to read the alternate file if 107118611Snjl * we get EFI_NOT_FOUND because all other errors mean that the boot_module 108118611Snjl * had troubles with the filesystem. We could return early, but we'll let 109118611Snjl * loading the actual kernel sort all that out. Since these files are 110118611Snjl * optional, we don't report errors in trying to read them. 111118611Snjl */ 112118611Snjl cmd = NULL; 113118611Snjl cmdsize = 0; 114118611Snjl status = mod->load(PATH_DOTCONFIG, &dev, &buf, &bufsize); 115118611Snjl if (status == EFI_NOT_FOUND) 116118611Snjl status = mod->load(PATH_CONFIG, &dev, &buf, &bufsize); 117118611Snjl if (status == EFI_SUCCESS) { 118151937Sjkim cmdsize = bufsize + 1; 119118611Snjl cmd = malloc(cmdsize); 120118611Snjl if (cmd == NULL) { 121118611Snjl free(buf); 122118611Snjl return; 123228110Sjkim } 124228110Sjkim memcpy(cmd, buf, bufsize); 125228110Sjkim cmd[bufsize] = '\0'; 126241973Sjkim free(buf); 127238381Sjkim } 128197104Sjkim 129233250Sjkim status = mod->load(PATH_LOADER_EFI, &dev, &buf, &bufsize); 130233250Sjkim if (status == EFI_NOT_FOUND) 131233250Sjkim return; 132233250Sjkim 133234623Sjkim if (status != EFI_SUCCESS) { 134233250Sjkim printf("%s failed to load %s (%lu)\n", mod->name, 135197104Sjkim PATH_LOADER_EFI, EFI_ERROR_CODE(status)); 136228110Sjkim return; 137228110Sjkim } 138228110Sjkim 139228110Sjkim if ((status = bs->LoadImage(TRUE, image, dev->devpath, buf, bufsize, 140228110Sjkim &loaderhandle)) != EFI_SUCCESS) { 141228110Sjkim printf("Failed to load image provided by %s, size: %zu, (%lu)\n", 142233250Sjkim mod->name, bufsize, EFI_ERROR_CODE(status)); 143234623Sjkim return; 144118611Snjl } 145241973Sjkim 146241973Sjkim if (cmd != NULL) 147233250Sjkim printf(" command args: %s\n", cmd); 148241973Sjkim 149118611Snjl if ((status = bs->HandleProtocol(loaderhandle, &LoadedImageGUID, 150138287Smarks (VOID**)&loaded_image)) != EFI_SUCCESS) { 151228110Sjkim printf("Failed to query LoadedImage provided by %s (%lu)\n", 152228110Sjkim mod->name, EFI_ERROR_CODE(status)); 153228110Sjkim return; 154228110Sjkim } 155228110Sjkim 156228110Sjkim loaded_image->DeviceHandle = dev->devhandle; 157118611Snjl loaded_image->LoadOptionsSize = cmdsize; 158212761Sjkim loaded_image->LoadOptions = cmd; 159228110Sjkim 160228110Sjkim if ((status = bs->StartImage(loaderhandle, NULL, NULL)) != 161228110Sjkim EFI_SUCCESS) { 162118611Snjl printf("Failed to start image provided by %s (%lu)\n", 163209746Sjkim mod->name, EFI_ERROR_CODE(status)); 164228110Sjkim free(cmd); 165228110Sjkim loaded_image->LoadOptionsSize = 0; 166209746Sjkim loaded_image->LoadOptions = NULL; 167118611Snjl return; 168228110Sjkim } 169228110Sjkim} 170240716Sjkim 171228110SjkimEFI_STATUS 172228110Sjkimefi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE *Xsystab) 173228110Sjkim{ 174228110Sjkim EFI_HANDLE *handles; 175228110Sjkim EFI_STATUS status; 176241973Sjkim EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl = NULL; 177118611Snjl SIMPLE_TEXT_OUTPUT_INTERFACE *conout = NULL; 178118611Snjl UINTN i, max_dim, best_mode, cols, rows, hsize, nhandles; 179237412Sjkim 180228110Sjkim /* Basic initialization*/ 181237412Sjkim systab = Xsystab; 182228110Sjkim image = Ximage; 183228110Sjkim bs = Xsystab->BootServices; 184237412Sjkim 185237412Sjkim /* Set up the console, so printf works. */ 186237412Sjkim status = bs->LocateProtocol(&ConsoleControlGUID, NULL, 187237412Sjkim (VOID **)&ConsoleControl); 188237412Sjkim if (status == EFI_SUCCESS) 189237412Sjkim (void)ConsoleControl->SetMode(ConsoleControl, 190237412Sjkim EfiConsoleControlScreenText); 191237412Sjkim /* 192118611Snjl * Reset the console and find the best text mode. 193118611Snjl */ 194118611Snjl conout = systab->ConOut; 195118611Snjl conout->Reset(conout, TRUE); 196118611Snjl max_dim = best_mode = 0; 197237412Sjkim for (i = 0; ; i++) { 198118611Snjl status = conout->QueryMode(conout, i, &cols, &rows); 199118611Snjl if (EFI_ERROR(status)) 200118611Snjl break; 201118611Snjl if (cols * rows > max_dim) { 202118611Snjl max_dim = cols * rows; 203237412Sjkim best_mode = i; 204118611Snjl } 205118611Snjl } 206118611Snjl if (max_dim > 0) 207151937Sjkim conout->SetMode(conout, best_mode); 208237412Sjkim conout->EnableCursor(conout, TRUE); 209118611Snjl conout->ClearScreen(conout); 210118611Snjl 211118611Snjl printf("\n>> FreeBSD EFI boot block\n"); 212228110Sjkim printf(" Loader path: %s\n\n", PATH_LOADER_EFI); 213118611Snjl printf(" Initializing modules:"); 214241973Sjkim for (i = 0; i < NUM_BOOT_MODULES; i++) { 215118611Snjl if (boot_modules[i] == NULL) 216118611Snjl continue; 217118611Snjl 218118611Snjl printf(" %s", boot_modules[i]->name); 219118611Snjl if (boot_modules[i]->init != NULL) 220118611Snjl boot_modules[i]->init(); 221118611Snjl } 222118611Snjl putchar('\n'); 223118611Snjl 224118611Snjl /* Get all the device handles */ 225118611Snjl hsize = (UINTN)NUM_HANDLES_INIT * sizeof(EFI_HANDLE); 226118611Snjl if ((status = bs->AllocatePool(EfiLoaderData, hsize, (void **)&handles)) 227118611Snjl != EFI_SUCCESS) 228118611Snjl panic("Failed to allocate %d handles (%lu)", NUM_HANDLES_INIT, 229118611Snjl EFI_ERROR_CODE(status)); 230118611Snjl 231118611Snjl status = bs->LocateHandle(ByProtocol, &BlockIoProtocolGUID, NULL, 232118611Snjl &hsize, handles); 233118611Snjl switch (status) { 234118611Snjl case EFI_SUCCESS: 235151937Sjkim break; 236118611Snjl case EFI_BUFFER_TOO_SMALL: 237118611Snjl (void)bs->FreePool(handles); 238118611Snjl if ((status = bs->AllocatePool(EfiLoaderData, hsize, 239118611Snjl (void **)&handles) != EFI_SUCCESS)) { 240228110Sjkim panic("Failed to allocate %zu handles (%lu)", hsize / 241228110Sjkim sizeof(*handles), EFI_ERROR_CODE(status)); 242118611Snjl } 243118611Snjl status = bs->LocateHandle(ByProtocol, &BlockIoProtocolGUID, 244118611Snjl NULL, &hsize, handles); 245118611Snjl if (status != EFI_SUCCESS) 246240716Sjkim panic("Failed to get device handles (%lu)\n", 247240716Sjkim EFI_ERROR_CODE(status)); 248240716Sjkim break; 249240716Sjkim default: 250240716Sjkim panic("Failed to get device handles (%lu)", 251240716Sjkim EFI_ERROR_CODE(status)); 252240716Sjkim } 253240716Sjkim 254240716Sjkim /* Scan all partitions, probing with all modules. */ 255240716Sjkim nhandles = hsize / sizeof(*handles); 256240716Sjkim printf(" Probing %zu block devices...", nhandles); 257240716Sjkim for (i = 0; i < nhandles; i++) { 258240716Sjkim status = probe_handle(handles[i]); 259240716Sjkim switch (status) { 260240716Sjkim case EFI_UNSUPPORTED: 261240716Sjkim printf("."); 262240716Sjkim break; 263240716Sjkim case EFI_SUCCESS: 264240716Sjkim printf("+"); 265240716Sjkim break; 266240716Sjkim default: 267240716Sjkim printf("x"); 268240716Sjkim break; 269240716Sjkim } 270240716Sjkim } 271240716Sjkim printf(" done\n"); 272240716Sjkim 273240716Sjkim /* Status summary. */ 274240716Sjkim for (i = 0; i < NUM_BOOT_MODULES; i++) { 275240716Sjkim if (boot_modules[i] != NULL) { 276240716Sjkim printf(" "); 277240716Sjkim boot_modules[i]->status(); 278240716Sjkim } 279240716Sjkim } 280240716Sjkim 281240716Sjkim /* Select a partition to boot by trying each module in order. */ 282240716Sjkim for (i = 0; i < NUM_BOOT_MODULES; i++) 283240716Sjkim if (boot_modules[i] != NULL) 284240716Sjkim try_load(boot_modules[i]); 285240716Sjkim 286240716Sjkim /* If we get here, we're out of luck... */ 287240716Sjkim panic("No bootable partitions found!"); 288240716Sjkim} 289118611Snjl 290118611Snjlstatic EFI_STATUS 291118611Snjlprobe_handle(EFI_HANDLE h) 292118611Snjl{ 293118611Snjl dev_info_t *devinfo; 294118611Snjl EFI_BLOCK_IO *blkio; 295118611Snjl EFI_DEVICE_PATH *devpath; 296118611Snjl EFI_STATUS status; 297118611Snjl UINTN i; 298118611Snjl 299118611Snjl /* Figure out if we're dealing with an actual partition. */ 300118611Snjl status = bs->HandleProtocol(h, &DevicePathGUID, (void **)&devpath); 301151937Sjkim if (status == EFI_UNSUPPORTED) 302151937Sjkim return (status); 303151937Sjkim 304118611Snjl if (status != EFI_SUCCESS) { 305118611Snjl DPRINTF("\nFailed to query DevicePath (%lu)\n", 306118611Snjl EFI_ERROR_CODE(status)); 307118611Snjl return (status); 308118611Snjl } 309118611Snjl 310118611Snjl while (!IsDevicePathEnd(NextDevicePathNode(devpath))) 311118611Snjl devpath = NextDevicePathNode(devpath); 312118611Snjl 313118611Snjl status = bs->HandleProtocol(h, &BlockIoProtocolGUID, (void **)&blkio); 314118611Snjl if (status == EFI_UNSUPPORTED) 315118611Snjl return (status); 316118611Snjl 317118611Snjl if (status != EFI_SUCCESS) { 318118611Snjl DPRINTF("\nFailed to query BlockIoProtocol (%lu)\n", 319118611Snjl EFI_ERROR_CODE(status)); 320118611Snjl return (status); 321118611Snjl } 322118611Snjl 323118611Snjl if (!blkio->Media->LogicalPartition) 324240716Sjkim return (EFI_UNSUPPORTED); 325240716Sjkim 326240716Sjkim /* Run through each module, see if it can load this partition */ 327240716Sjkim for (i = 0; i < NUM_BOOT_MODULES; i++) { 328240716Sjkim if (boot_modules[i] == NULL) 329118611Snjl continue; 330118611Snjl 331118611Snjl if ((status = bs->AllocatePool(EfiLoaderData, 332118611Snjl sizeof(*devinfo), (void **)&devinfo)) != 333118611Snjl EFI_SUCCESS) { 334197104Sjkim DPRINTF("\nFailed to allocate devinfo (%lu)\n", 335118611Snjl EFI_ERROR_CODE(status)); 336197104Sjkim continue; 337197104Sjkim } 338118611Snjl devinfo->dev = blkio; 339118611Snjl devinfo->devpath = devpath; 340118611Snjl devinfo->devhandle = h; 341197104Sjkim devinfo->devdata = NULL; 342118611Snjl devinfo->next = NULL; 343118611Snjl 344118611Snjl status = boot_modules[i]->probe(devinfo); 345197104Sjkim if (status == EFI_SUCCESS) 346197104Sjkim return (EFI_SUCCESS); 347197104Sjkim (void)bs->FreePool(devinfo); 348197104Sjkim } 349197104Sjkim 350197104Sjkim return (EFI_UNSUPPORTED); 351197104Sjkim} 352197104Sjkim 353197104Sjkimvoid 354197104Sjkimadd_device(dev_info_t **devinfop, dev_info_t *devinfo) 355197104Sjkim{ 356197104Sjkim dev_info_t *dev; 357197104Sjkim 358197104Sjkim if (*devinfop == NULL) { 359197104Sjkim *devinfop = devinfo; 360197104Sjkim return; 361197104Sjkim } 362197104Sjkim 363197104Sjkim for (dev = *devinfop; dev->next != NULL; dev = dev->next) 364197104Sjkim ; 365197104Sjkim 366197104Sjkim dev->next = devinfo; 367197104Sjkim} 368197104Sjkim 369197104Sjkimvoid 370197104Sjkimpanic(const char *fmt, ...) 371197104Sjkim{ 372197104Sjkim va_list ap; 373197104Sjkim 374197104Sjkim printf("panic: "); 375197104Sjkim va_start(ap, fmt); 376193529Sjkim vprintf(fmt, ap); 377197104Sjkim va_end(ap); 378197104Sjkim printf("\n"); 379118611Snjl 380197104Sjkim while (1) {} 381197104Sjkim} 382197104Sjkim 383197104Sjkimvoid 384197104Sjkimputchar(int c) 385118611Snjl{ 386118611Snjl CHAR16 buf[2]; 387197104Sjkim 388197104Sjkim if (c == '\n') { 389197104Sjkim buf[0] = '\r'; 390197104Sjkim buf[1] = 0; 391197104Sjkim systab->ConOut->OutputString(systab->ConOut, buf); 392241973Sjkim } 393197104Sjkim buf[0] = c; 394118611Snjl buf[1] = 0; 395197104Sjkim systab->ConOut->OutputString(systab->ConOut, buf); 396197104Sjkim} 397197104Sjkim