boot1.c revision 294720
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: stable/10/sys/boot/efi/boot1/boot1.c 294720 2016-01-25 10:50:11Z smh $"); 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 62EFI_SYSTEM_TABLE *systab; 63EFI_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, &cols, &rows); 136 if (EFI_ERROR(status)) 137 break; 138 if (cols * rows > max_dim) { 139 max_dim = cols * rows; 140 best_mode = i; 141 } 142 } 143 if (max_dim > 0) 144 conout->SetMode(conout, best_mode); 145 conout->EnableCursor(conout, TRUE); 146 conout->ClearScreen(conout); 147 148 printf(" \n>> FreeBSD EFI boot block\n"); 149 printf(" Loader path: %s\n", path); 150 151 status = systab->BootServices->LocateHandle(ByProtocol, 152 &BlockIoProtocolGUID, NULL, &nparts, handles); 153 nparts /= sizeof(handles[0]); 154 155 for (i = 0; i < nparts; i++) { 156 status = systab->BootServices->HandleProtocol(handles[i], 157 &DevicePathGUID, (void **)&devpath); 158 if (EFI_ERROR(status)) 159 continue; 160 161 while (!IsDevicePathEnd(NextDevicePathNode(devpath))) 162 devpath = NextDevicePathNode(devpath); 163 164 status = systab->BootServices->HandleProtocol(handles[i], 165 &BlockIoProtocolGUID, (void **)&blkio); 166 if (EFI_ERROR(status)) 167 continue; 168 169 if (!blkio->Media->LogicalPartition) 170 continue; 171 172 if (domount(devpath, blkio, 1) >= 0) 173 break; 174 } 175 176 if (i == nparts) 177 panic("No bootable partition found"); 178 179 bootdevhandle = handles[i]; 180 load(path); 181 182 panic("Load failed"); 183 184 return EFI_SUCCESS; 185} 186 187static int 188dskread(void *buf, u_int64_t lba, int nblk) 189{ 190 EFI_STATUS status; 191 int size; 192 193 lba = lba / (bootdev->Media->BlockSize / DEV_BSIZE); 194 size = nblk * DEV_BSIZE; 195 status = bootdev->ReadBlocks(bootdev, bootdev->Media->MediaId, lba, 196 size, buf); 197 198 if (EFI_ERROR(status)) 199 return (-1); 200 201 return (0); 202} 203 204#include "ufsread.c" 205 206static ssize_t 207fsstat(ufs_ino_t inode) 208{ 209#ifndef UFS2_ONLY 210 static struct ufs1_dinode dp1; 211 ufs1_daddr_t addr1; 212#endif 213#ifndef UFS1_ONLY 214 static struct ufs2_dinode dp2; 215#endif 216 static struct fs fs; 217 static ufs_ino_t inomap; 218 char *blkbuf; 219 void *indbuf; 220 size_t n, nb, size, off, vboff; 221 ufs_lbn_t lbn; 222 ufs2_daddr_t addr2, vbaddr; 223 static ufs2_daddr_t blkmap, indmap; 224 u_int u; 225 226 blkbuf = dmadat->blkbuf; 227 indbuf = dmadat->indbuf; 228 if (!dsk_meta) { 229 inomap = 0; 230 for (n = 0; sblock_try[n] != -1; n++) { 231 if (dskread(dmadat->sbbuf, sblock_try[n] / DEV_BSIZE, 232 SBLOCKSIZE / DEV_BSIZE)) 233 return -1; 234 memcpy(&fs, dmadat->sbbuf, sizeof(struct fs)); 235 if (( 236#if defined(UFS1_ONLY) 237 fs.fs_magic == FS_UFS1_MAGIC 238#elif defined(UFS2_ONLY) 239 (fs.fs_magic == FS_UFS2_MAGIC && 240 fs.fs_sblockloc == sblock_try[n]) 241#else 242 fs.fs_magic == FS_UFS1_MAGIC || 243 (fs.fs_magic == FS_UFS2_MAGIC && 244 fs.fs_sblockloc == sblock_try[n]) 245#endif 246 ) && 247 fs.fs_bsize <= MAXBSIZE && 248 fs.fs_bsize >= sizeof(struct fs)) 249 break; 250 } 251 if (sblock_try[n] == -1) { 252 printf("Not ufs\n"); 253 return -1; 254 } 255 dsk_meta++; 256 } else 257 memcpy(&fs, dmadat->sbbuf, sizeof(struct fs)); 258 if (!inode) 259 return 0; 260 if (inomap != inode) { 261 n = IPERVBLK(&fs); 262 if (dskread(blkbuf, INO_TO_VBA(&fs, n, inode), DBPERVBLK)) 263 return -1; 264 n = INO_TO_VBO(n, inode); 265#if defined(UFS1_ONLY) 266 memcpy(&dp1, (struct ufs1_dinode *)blkbuf + n, 267 sizeof(struct ufs1_dinode)); 268#elif defined(UFS2_ONLY) 269 memcpy(&dp2, (struct ufs2_dinode *)blkbuf + n, 270 sizeof(struct ufs2_dinode)); 271#else 272 if (fs.fs_magic == FS_UFS1_MAGIC) 273 memcpy(&dp1, (struct ufs1_dinode *)blkbuf + n, 274 sizeof(struct ufs1_dinode)); 275 else 276 memcpy(&dp2, (struct ufs2_dinode *)blkbuf + n, 277 sizeof(struct ufs2_dinode)); 278#endif 279 inomap = inode; 280 fs_off = 0; 281 blkmap = indmap = 0; 282 } 283 size = DIP(di_size); 284 n = size - fs_off; 285 return (n); 286} 287 288static struct dmadat __dmadat; 289 290static int 291domount(EFI_DEVICE_PATH *device, EFI_BLOCK_IO *blkio, int quiet) 292{ 293 294 dmadat = &__dmadat; 295 bootdev = blkio; 296 bootdevpath = device; 297 if (fsread(0, NULL, 0)) { 298 if (!quiet) 299 printf("domount: can't read superblock\n"); 300 return (-1); 301 } 302 if (!quiet) 303 printf("Succesfully mounted UFS filesystem\n"); 304 return (0); 305} 306 307static void 308load(const char *fname) 309{ 310 ufs_ino_t ino; 311 EFI_STATUS status; 312 EFI_HANDLE loaderhandle; 313 EFI_LOADED_IMAGE *loaded_image; 314 void *buffer; 315 size_t bufsize; 316 317 if ((ino = lookup(fname)) == 0) { 318 printf("File %s not found\n", fname); 319 return; 320 } 321 322 bufsize = fsstat(ino); 323 status = systab->BootServices->AllocatePool(EfiLoaderData, 324 bufsize, &buffer); 325 fsread(ino, buffer, bufsize); 326 327 /* XXX: For secure boot, we need our own loader here */ 328 status = systab->BootServices->LoadImage(TRUE, image, bootdevpath, 329 buffer, bufsize, &loaderhandle); 330 if (EFI_ERROR(status)) 331 printf("LoadImage failed with error %lu\n", 332 EFI_ERROR_CODE(status)); 333 334 status = systab->BootServices->HandleProtocol(loaderhandle, 335 &LoadedImageGUID, (VOID**)&loaded_image); 336 if (EFI_ERROR(status)) 337 printf("HandleProtocol failed with error %lu\n", 338 EFI_ERROR_CODE(status)); 339 340 loaded_image->DeviceHandle = bootdevhandle; 341 342 status = systab->BootServices->StartImage(loaderhandle, NULL, NULL); 343 if (EFI_ERROR(status)) 344 printf("StartImage failed with error %lu\n", 345 EFI_ERROR_CODE(status)); 346} 347 348static void 349panic(const char *fmt, ...) 350{ 351 char buf[128]; 352 va_list ap; 353 354 va_start(ap, fmt); 355 vsnprintf(buf, sizeof buf, fmt, ap); 356 printf("panic: %s\n", buf); 357 va_end(ap); 358 359 while (1) {} 360} 361 362static int 363printf(const char *fmt, ...) 364{ 365 va_list ap; 366 int ret; 367 368 /* Don't annoy the user as we probe for partitions */ 369 if (strcmp(fmt,"Not ufs\n") == 0) 370 return 0; 371 372 va_start(ap, fmt); 373 ret = vprintf(fmt, ap); 374 va_end(ap); 375 return (ret); 376} 377 378static int 379putchar(char c, void *arg) 380{ 381 CHAR16 buf[2]; 382 383 if (c == '\n') { 384 buf[0] = '\r'; 385 buf[1] = 0; 386 systab->ConOut->OutputString(systab->ConOut, buf); 387 } 388 buf[0] = c; 389 buf[1] = 0; 390 systab->ConOut->OutputString(systab->ConOut, buf); 391 return (1); 392} 393 394static int 395vprintf(const char *fmt, va_list ap) 396{ 397 int ret; 398 399 ret = __printf(fmt, putchar, 0, ap); 400 return (ret); 401} 402 403static int 404vsnprintf(char *str, size_t sz, const char *fmt, va_list ap) 405{ 406 struct sp_data sp; 407 int ret; 408 409 sp.sp_buf = str; 410 sp.sp_len = 0; 411 sp.sp_size = sz; 412 ret = __printf(fmt, __sputc, &sp, ap); 413 return (ret); 414} 415 416static int 417__printf(const char *fmt, putc_func_t *putc, void *arg, va_list ap) 418{ 419 char buf[(sizeof(long) * 8) + 1]; 420 char *nbuf; 421 u_long ul; 422 u_int ui; 423 int lflag; 424 int sflag; 425 char *s; 426 int pad; 427 int ret; 428 int c; 429 430 nbuf = &buf[sizeof buf - 1]; 431 ret = 0; 432 while ((c = *fmt++) != 0) { 433 if (c != '%') { 434 ret += putc(c, arg); 435 continue; 436 } 437 lflag = 0; 438 sflag = 0; 439 pad = 0; 440reswitch: c = *fmt++; 441 switch (c) { 442 case '#': 443 sflag = 1; 444 goto reswitch; 445 case '%': 446 ret += putc('%', arg); 447 break; 448 case 'c': 449 c = va_arg(ap, int); 450 ret += putc(c, arg); 451 break; 452 case 'd': 453 if (lflag == 0) { 454 ui = (u_int)va_arg(ap, int); 455 if (ui < (int)ui) { 456 ui = -ui; 457 ret += putc('-', arg); 458 } 459 s = __uitoa(nbuf, ui, 10); 460 } else { 461 ul = (u_long)va_arg(ap, long); 462 if (ul < (long)ul) { 463 ul = -ul; 464 ret += putc('-', arg); 465 } 466 s = __ultoa(nbuf, ul, 10); 467 } 468 ret += __puts(s, putc, arg); 469 break; 470 case 'l': 471 lflag = 1; 472 goto reswitch; 473 case 'o': 474 if (lflag == 0) { 475 ui = (u_int)va_arg(ap, u_int); 476 s = __uitoa(nbuf, ui, 8); 477 } else { 478 ul = (u_long)va_arg(ap, u_long); 479 s = __ultoa(nbuf, ul, 8); 480 } 481 ret += __puts(s, putc, arg); 482 break; 483 case 'p': 484 ul = (u_long)va_arg(ap, void *); 485 s = __ultoa(nbuf, ul, 16); 486 ret += __puts("0x", putc, arg); 487 ret += __puts(s, putc, arg); 488 break; 489 case 's': 490 s = va_arg(ap, char *); 491 ret += __puts(s, putc, arg); 492 break; 493 case 'u': 494 if (lflag == 0) { 495 ui = va_arg(ap, u_int); 496 s = __uitoa(nbuf, ui, 10); 497 } else { 498 ul = va_arg(ap, u_long); 499 s = __ultoa(nbuf, ul, 10); 500 } 501 ret += __puts(s, putc, arg); 502 break; 503 case 'x': 504 if (lflag == 0) { 505 ui = va_arg(ap, u_int); 506 s = __uitoa(nbuf, ui, 16); 507 } else { 508 ul = va_arg(ap, u_long); 509 s = __ultoa(nbuf, ul, 16); 510 } 511 if (sflag) 512 ret += __puts("0x", putc, arg); 513 ret += __puts(s, putc, arg); 514 break; 515 case '0': case '1': case '2': case '3': case '4': 516 case '5': case '6': case '7': case '8': case '9': 517 pad = pad * 10 + c - '0'; 518 goto reswitch; 519 default: 520 break; 521 } 522 } 523 return (ret); 524} 525 526static int 527__sputc(char c, void *arg) 528{ 529 struct sp_data *sp; 530 531 sp = arg; 532 if (sp->sp_len < sp->sp_size) 533 sp->sp_buf[sp->sp_len++] = c; 534 sp->sp_buf[sp->sp_len] = '\0'; 535 return (1); 536} 537 538static int 539__puts(const char *s, putc_func_t *putc, void *arg) 540{ 541 const char *p; 542 int ret; 543 544 ret = 0; 545 for (p = s; *p != '\0'; p++) 546 ret += putc(*p, arg); 547 return (ret); 548} 549 550static char * 551__uitoa(char *buf, u_int ui, int base) 552{ 553 char *p; 554 555 p = buf; 556 *p = '\0'; 557 do 558 *--p = digits[ui % base]; 559 while ((ui /= base) != 0); 560 return (p); 561} 562 563static char * 564__ultoa(char *buf, u_long ul, int base) 565{ 566 char *p; 567 568 p = buf; 569 *p = '\0'; 570 do 571 *--p = digits[ul % base]; 572 while ((ul /= base) != 0); 573 return (p); 574} 575