boot1.c revision 292576
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 * 9 * Redistribution and use in source and binary forms are freely 10 * permitted provided that the above copyright notice and this 11 * paragraph and the following disclaimer are duplicated in all 12 * such forms. 13 * 14 * This software is provided "AS IS" and without any express or 15 * implied warranties, including, without limitation, the implied 16 * warranties of merchantability and fitness for a particular 17 * purpose. 18 */ 19 20#include <sys/cdefs.h> 21__FBSDID("$FreeBSD: head/sys/boot/efi/boot1/boot1.c 292576 2015-12-21 22:42:03Z emaste $"); 22 23#include <sys/param.h> 24#include <sys/dirent.h> 25#include <machine/elf.h> 26#include <machine/stdarg.h> 27 28#include <efi.h> 29#include <eficonsctl.h> 30 31#define _PATH_LOADER "/boot/loader.efi" 32#define _PATH_KERNEL "/boot/kernel/kernel" 33 34#define BSIZEMAX 16384 35 36typedef int putc_func_t(char c, void *arg); 37 38struct sp_data { 39 char *sp_buf; 40 u_int sp_len; 41 u_int sp_size; 42}; 43 44static const char digits[] = "0123456789abcdef"; 45 46static void panic(const char *fmt, ...) __dead2; 47static int printf(const char *fmt, ...); 48static int putchar(char c, void *arg); 49static int vprintf(const char *fmt, va_list ap); 50static int vsnprintf(char *str, size_t sz, const char *fmt, va_list ap); 51 52static int __printf(const char *fmt, putc_func_t *putc, void *arg, va_list ap); 53static int __putc(char c, void *arg); 54static int __puts(const char *s, putc_func_t *putc, void *arg); 55static int __sputc(char c, void *arg); 56static char *__uitoa(char *buf, u_int val, int base); 57static char *__ultoa(char *buf, u_long val, int base); 58 59static int domount(EFI_DEVICE_PATH *device, EFI_BLOCK_IO *blkio, int quiet); 60static void load(const char *fname); 61 62static EFI_SYSTEM_TABLE *systab; 63static EFI_HANDLE *image; 64 65static void 66bcopy(const void *src, void *dst, size_t len) 67{ 68 const char *s = src; 69 char *d = dst; 70 71 while (len-- != 0) 72 *d++ = *s++; 73} 74 75static void 76memcpy(void *dst, const void *src, size_t len) 77{ 78 bcopy(src, dst, len); 79} 80 81static void 82bzero(void *b, size_t len) 83{ 84 char *p = b; 85 86 while (len-- != 0) 87 *p++ = 0; 88} 89 90static int 91strcmp(const char *s1, const char *s2) 92{ 93 for (; *s1 == *s2 && *s1; s1++, s2++) 94 ; 95 return ((u_char)*s1 - (u_char)*s2); 96} 97 98static EFI_GUID BlockIoProtocolGUID = BLOCK_IO_PROTOCOL; 99static EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL; 100static EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL; 101static EFI_GUID ConsoleControlGUID = EFI_CONSOLE_CONTROL_PROTOCOL_GUID; 102 103static EFI_BLOCK_IO *bootdev; 104static EFI_DEVICE_PATH *bootdevpath; 105static EFI_HANDLE *bootdevhandle; 106 107EFI_STATUS efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE* Xsystab) 108{ 109 EFI_HANDLE handles[128]; 110 EFI_BLOCK_IO *blkio; 111 UINTN i, nparts = sizeof(handles), cols, rows, max_dim, best_mode; 112 EFI_STATUS status; 113 EFI_DEVICE_PATH *devpath; 114 EFI_BOOT_SERVICES *BS; 115 EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl = NULL; 116 SIMPLE_TEXT_OUTPUT_INTERFACE *conout = NULL; 117 char *path = _PATH_LOADER; 118 119 systab = Xsystab; 120 image = Ximage; 121 122 BS = systab->BootServices; 123 status = BS->LocateProtocol(&ConsoleControlGUID, NULL, 124 (VOID **)&ConsoleControl); 125 if (status == EFI_SUCCESS) 126 (void)ConsoleControl->SetMode(ConsoleControl, 127 EfiConsoleControlScreenText); 128 /* 129 * Reset the console and find the best text mode. 130 */ 131 conout = systab->ConOut; 132 conout->Reset(conout, TRUE); 133 max_dim = best_mode = 0; 134 for (i = 0; ; i++) { 135 status = conout->QueryMode(conout, i, 136 &cols, &rows); 137 if (EFI_ERROR(status)) 138 break; 139 if (cols * rows > max_dim) { 140 max_dim = cols * rows; 141 best_mode = i; 142 } 143 } 144 if (max_dim > 0) 145 conout->SetMode(conout, best_mode); 146 conout->EnableCursor(conout, TRUE); 147 conout->ClearScreen(conout); 148 149 printf("\n" 150 ">> FreeBSD EFI boot block\n"); 151 printf(" Loader path: %s\n", path); 152 153 status = systab->BootServices->LocateHandle(ByProtocol, 154 &BlockIoProtocolGUID, NULL, &nparts, handles); 155 nparts /= sizeof(handles[0]); 156 157 for (i = 0; i < nparts; i++) { 158 status = systab->BootServices->HandleProtocol(handles[i], 159 &DevicePathGUID, (void **)&devpath); 160 if (EFI_ERROR(status)) 161 continue; 162 163 while (!IsDevicePathEnd(NextDevicePathNode(devpath))) 164 devpath = NextDevicePathNode(devpath); 165 166 status = systab->BootServices->HandleProtocol(handles[i], 167 &BlockIoProtocolGUID, (void **)&blkio); 168 if (EFI_ERROR(status)) 169 continue; 170 171 if (!blkio->Media->LogicalPartition) 172 continue; 173 174 if (domount(devpath, blkio, 1) >= 0) 175 break; 176 } 177 178 if (i == nparts) 179 panic("No bootable partition found"); 180 181 bootdevhandle = handles[i]; 182 load(path); 183 184 panic("Load failed"); 185 186 return EFI_SUCCESS; 187} 188 189static int 190dskread(void *buf, u_int64_t lba, int nblk) 191{ 192 EFI_STATUS status; 193 int size; 194 195 lba = lba / (bootdev->Media->BlockSize / DEV_BSIZE); 196 size = nblk * DEV_BSIZE; 197 status = bootdev->ReadBlocks(bootdev, bootdev->Media->MediaId, lba, 198 size, buf); 199 200 if (EFI_ERROR(status)) 201 return (-1); 202 203 return (0); 204} 205 206#include "ufsread.c" 207 208static ssize_t 209fsstat(ufs_ino_t inode) 210{ 211#ifndef UFS2_ONLY 212 static struct ufs1_dinode dp1; 213 ufs1_daddr_t addr1; 214#endif 215#ifndef UFS1_ONLY 216 static struct ufs2_dinode dp2; 217#endif 218 static struct fs fs; 219 static ufs_ino_t inomap; 220 char *blkbuf; 221 void *indbuf; 222 size_t n, nb, size, off, vboff; 223 ufs_lbn_t lbn; 224 ufs2_daddr_t addr2, vbaddr; 225 static ufs2_daddr_t blkmap, indmap; 226 u_int u; 227 228 blkbuf = dmadat->blkbuf; 229 indbuf = dmadat->indbuf; 230 if (!dsk_meta) { 231 inomap = 0; 232 for (n = 0; sblock_try[n] != -1; n++) { 233 if (dskread(dmadat->sbbuf, sblock_try[n] / DEV_BSIZE, 234 SBLOCKSIZE / DEV_BSIZE)) 235 return -1; 236 memcpy(&fs, dmadat->sbbuf, sizeof(struct fs)); 237 if (( 238#if defined(UFS1_ONLY) 239 fs.fs_magic == FS_UFS1_MAGIC 240#elif defined(UFS2_ONLY) 241 (fs.fs_magic == FS_UFS2_MAGIC && 242 fs.fs_sblockloc == sblock_try[n]) 243#else 244 fs.fs_magic == FS_UFS1_MAGIC || 245 (fs.fs_magic == FS_UFS2_MAGIC && 246 fs.fs_sblockloc == sblock_try[n]) 247#endif 248 ) && 249 fs.fs_bsize <= MAXBSIZE && 250 fs.fs_bsize >= sizeof(struct fs)) 251 break; 252 } 253 if (sblock_try[n] == -1) { 254 printf("Not ufs\n"); 255 return -1; 256 } 257 dsk_meta++; 258 } else 259 memcpy(&fs, dmadat->sbbuf, sizeof(struct fs)); 260 if (!inode) 261 return 0; 262 if (inomap != inode) { 263 n = IPERVBLK(&fs); 264 if (dskread(blkbuf, INO_TO_VBA(&fs, n, inode), DBPERVBLK)) 265 return -1; 266 n = INO_TO_VBO(n, inode); 267#if defined(UFS1_ONLY) 268 memcpy(&dp1, (struct ufs1_dinode *)blkbuf + n, 269 sizeof(struct ufs1_dinode)); 270#elif defined(UFS2_ONLY) 271 memcpy(&dp2, (struct ufs2_dinode *)blkbuf + n, 272 sizeof(struct ufs2_dinode)); 273#else 274 if (fs.fs_magic == FS_UFS1_MAGIC) 275 memcpy(&dp1, (struct ufs1_dinode *)blkbuf + n, 276 sizeof(struct ufs1_dinode)); 277 else 278 memcpy(&dp2, (struct ufs2_dinode *)blkbuf + n, 279 sizeof(struct ufs2_dinode)); 280#endif 281 inomap = inode; 282 fs_off = 0; 283 blkmap = indmap = 0; 284 } 285 size = DIP(di_size); 286 n = size - fs_off; 287 return (n); 288} 289 290static struct dmadat __dmadat; 291 292static int 293domount(EFI_DEVICE_PATH *device, EFI_BLOCK_IO *blkio, int quiet) 294{ 295 296 dmadat = &__dmadat; 297 bootdev = blkio; 298 bootdevpath = device; 299 if (fsread(0, NULL, 0)) { 300 if (!quiet) 301 printf("domount: can't read superblock\n"); 302 return (-1); 303 } 304 if (!quiet) 305 printf("Succesfully mounted UFS filesystem\n"); 306 return (0); 307} 308 309static void 310load(const char *fname) 311{ 312 ufs_ino_t ino; 313 EFI_STATUS status; 314 EFI_HANDLE loaderhandle; 315 EFI_LOADED_IMAGE *loaded_image; 316 void *buffer; 317 size_t bufsize; 318 319 if ((ino = lookup(fname)) == 0) { 320 printf("File %s not found\n", fname); 321 return; 322 } 323 324 bufsize = fsstat(ino); 325 status = systab->BootServices->AllocatePool(EfiLoaderData, 326 bufsize, &buffer); 327 fsread(ino, buffer, bufsize); 328 329 /* XXX: For secure boot, we need our own loader here */ 330 status = systab->BootServices->LoadImage(TRUE, image, bootdevpath, 331 buffer, bufsize, &loaderhandle); 332 if (EFI_ERROR(status)) 333 printf("LoadImage failed with error %lu\n", 334 status & ~EFI_ERROR_MASK); 335 336 status = systab->BootServices->HandleProtocol(loaderhandle, 337 &LoadedImageGUID, (VOID**)&loaded_image); 338 if (EFI_ERROR(status)) 339 printf("HandleProtocol failed with error %lu\n", 340 status & ~EFI_ERROR_MASK); 341 342 loaded_image->DeviceHandle = bootdevhandle; 343 344 status = systab->BootServices->StartImage(loaderhandle, NULL, NULL); 345 if (EFI_ERROR(status)) 346 printf("StartImage failed with error %lu\n", 347 status & ~EFI_ERROR_MASK); 348} 349 350static void 351panic(const char *fmt, ...) 352{ 353 char buf[128]; 354 va_list ap; 355 356 va_start(ap, fmt); 357 vsnprintf(buf, sizeof buf, fmt, ap); 358 printf("panic: %s\n", buf); 359 va_end(ap); 360 361 while (1) {} 362} 363 364static int 365printf(const char *fmt, ...) 366{ 367 va_list ap; 368 int ret; 369 370 /* Don't annoy the user as we probe for partitions */ 371 if (strcmp(fmt,"Not ufs\n") == 0) 372 return 0; 373 374 va_start(ap, fmt); 375 ret = vprintf(fmt, ap); 376 va_end(ap); 377 return (ret); 378} 379 380static int 381putchar(char c, void *arg) 382{ 383 CHAR16 buf[2]; 384 385 if (c == '\n') { 386 buf[0] = '\r'; 387 buf[1] = 0; 388 systab->ConOut->OutputString(systab->ConOut, buf); 389 } 390 buf[0] = c; 391 buf[1] = 0; 392 systab->ConOut->OutputString(systab->ConOut, buf); 393 return (1); 394} 395 396static int 397vprintf(const char *fmt, va_list ap) 398{ 399 int ret; 400 401 ret = __printf(fmt, putchar, 0, ap); 402 return (ret); 403} 404 405static int 406vsnprintf(char *str, size_t sz, const char *fmt, va_list ap) 407{ 408 struct sp_data sp; 409 int ret; 410 411 sp.sp_buf = str; 412 sp.sp_len = 0; 413 sp.sp_size = sz; 414 ret = __printf(fmt, __sputc, &sp, ap); 415 return (ret); 416} 417 418static int 419__printf(const char *fmt, putc_func_t *putc, void *arg, va_list ap) 420{ 421 char buf[(sizeof(long) * 8) + 1]; 422 char *nbuf; 423 u_long ul; 424 u_int ui; 425 int lflag; 426 int sflag; 427 char *s; 428 int pad; 429 int ret; 430 int c; 431 432 nbuf = &buf[sizeof buf - 1]; 433 ret = 0; 434 while ((c = *fmt++) != 0) { 435 if (c != '%') { 436 ret += putc(c, arg); 437 continue; 438 } 439 lflag = 0; 440 sflag = 0; 441 pad = 0; 442reswitch: c = *fmt++; 443 switch (c) { 444 case '#': 445 sflag = 1; 446 goto reswitch; 447 case '%': 448 ret += putc('%', arg); 449 break; 450 case 'c': 451 c = va_arg(ap, int); 452 ret += putc(c, arg); 453 break; 454 case 'd': 455 if (lflag == 0) { 456 ui = (u_int)va_arg(ap, int); 457 if (ui < (int)ui) { 458 ui = -ui; 459 ret += putc('-', arg); 460 } 461 s = __uitoa(nbuf, ui, 10); 462 } else { 463 ul = (u_long)va_arg(ap, long); 464 if (ul < (long)ul) { 465 ul = -ul; 466 ret += putc('-', arg); 467 } 468 s = __ultoa(nbuf, ul, 10); 469 } 470 ret += __puts(s, putc, arg); 471 break; 472 case 'l': 473 lflag = 1; 474 goto reswitch; 475 case 'o': 476 if (lflag == 0) { 477 ui = (u_int)va_arg(ap, u_int); 478 s = __uitoa(nbuf, ui, 8); 479 } else { 480 ul = (u_long)va_arg(ap, u_long); 481 s = __ultoa(nbuf, ul, 8); 482 } 483 ret += __puts(s, putc, arg); 484 break; 485 case 'p': 486 ul = (u_long)va_arg(ap, void *); 487 s = __ultoa(nbuf, ul, 16); 488 ret += __puts("0x", putc, arg); 489 ret += __puts(s, putc, arg); 490 break; 491 case 's': 492 s = va_arg(ap, char *); 493 ret += __puts(s, putc, arg); 494 break; 495 case 'u': 496 if (lflag == 0) { 497 ui = va_arg(ap, u_int); 498 s = __uitoa(nbuf, ui, 10); 499 } else { 500 ul = va_arg(ap, u_long); 501 s = __ultoa(nbuf, ul, 10); 502 } 503 ret += __puts(s, putc, arg); 504 break; 505 case 'x': 506 if (lflag == 0) { 507 ui = va_arg(ap, u_int); 508 s = __uitoa(nbuf, ui, 16); 509 } else { 510 ul = va_arg(ap, u_long); 511 s = __ultoa(nbuf, ul, 16); 512 } 513 if (sflag) 514 ret += __puts("0x", putc, arg); 515 ret += __puts(s, putc, arg); 516 break; 517 case '0': case '1': case '2': case '3': case '4': 518 case '5': case '6': case '7': case '8': case '9': 519 pad = pad * 10 + c - '0'; 520 goto reswitch; 521 default: 522 break; 523 } 524 } 525 return (ret); 526} 527 528static int 529__sputc(char c, void *arg) 530{ 531 struct sp_data *sp; 532 533 sp = arg; 534 if (sp->sp_len < sp->sp_size) 535 sp->sp_buf[sp->sp_len++] = c; 536 sp->sp_buf[sp->sp_len] = '\0'; 537 return (1); 538} 539 540static int 541__puts(const char *s, putc_func_t *putc, void *arg) 542{ 543 const char *p; 544 int ret; 545 546 ret = 0; 547 for (p = s; *p != '\0'; p++) 548 ret += putc(*p, arg); 549 return (ret); 550} 551 552static char * 553__uitoa(char *buf, u_int ui, int base) 554{ 555 char *p; 556 557 p = buf; 558 *p = '\0'; 559 do 560 *--p = digits[ui % base]; 561 while ((ui /= base) != 0); 562 return (p); 563} 564 565static char * 566__ultoa(char *buf, u_long ul, int base) 567{ 568 char *p; 569 570 p = buf; 571 *p = '\0'; 572 do 573 *--p = digits[ul % base]; 574 while ((ul /= base) != 0); 575 return (p); 576} 577