boot1.c revision 294721
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 294721 2016-01-25 10:55:52Z 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 return -1; 253 } 254 dsk_meta++; 255 } else 256 memcpy(&fs, dmadat->sbbuf, sizeof(struct fs)); 257 if (!inode) 258 return 0; 259 if (inomap != inode) { 260 n = IPERVBLK(&fs); 261 if (dskread(blkbuf, INO_TO_VBA(&fs, n, inode), DBPERVBLK)) 262 return -1; 263 n = INO_TO_VBO(n, inode); 264#if defined(UFS1_ONLY) 265 memcpy(&dp1, (struct ufs1_dinode *)blkbuf + n, 266 sizeof(struct ufs1_dinode)); 267#elif defined(UFS2_ONLY) 268 memcpy(&dp2, (struct ufs2_dinode *)blkbuf + n, 269 sizeof(struct ufs2_dinode)); 270#else 271 if (fs.fs_magic == FS_UFS1_MAGIC) 272 memcpy(&dp1, (struct ufs1_dinode *)blkbuf + n, 273 sizeof(struct ufs1_dinode)); 274 else 275 memcpy(&dp2, (struct ufs2_dinode *)blkbuf + n, 276 sizeof(struct ufs2_dinode)); 277#endif 278 inomap = inode; 279 fs_off = 0; 280 blkmap = indmap = 0; 281 } 282 size = DIP(di_size); 283 n = size - fs_off; 284 return (n); 285} 286 287static struct dmadat __dmadat; 288 289static int 290domount(EFI_DEVICE_PATH *device, EFI_BLOCK_IO *blkio, int quiet) 291{ 292 293 dmadat = &__dmadat; 294 bootdev = blkio; 295 bootdevpath = device; 296 if (fsread(0, NULL, 0)) { 297 if (!quiet) 298 printf("domount: can't read superblock\n"); 299 return (-1); 300 } 301 if (!quiet) 302 printf("Succesfully mounted UFS filesystem\n"); 303 return (0); 304} 305 306static void 307load(const char *fname) 308{ 309 ufs_ino_t ino; 310 EFI_STATUS status; 311 EFI_HANDLE loaderhandle; 312 EFI_LOADED_IMAGE *loaded_image; 313 void *buffer; 314 size_t bufsize; 315 316 if ((ino = lookup(fname)) == 0) { 317 printf("File %s not found\n", fname); 318 return; 319 } 320 321 bufsize = fsstat(ino); 322 status = systab->BootServices->AllocatePool(EfiLoaderData, 323 bufsize, &buffer); 324 fsread(ino, buffer, bufsize); 325 326 /* XXX: For secure boot, we need our own loader here */ 327 status = systab->BootServices->LoadImage(TRUE, image, bootdevpath, 328 buffer, bufsize, &loaderhandle); 329 if (EFI_ERROR(status)) 330 printf("LoadImage failed with error %lu\n", 331 EFI_ERROR_CODE(status)); 332 333 status = systab->BootServices->HandleProtocol(loaderhandle, 334 &LoadedImageGUID, (VOID**)&loaded_image); 335 if (EFI_ERROR(status)) 336 printf("HandleProtocol failed with error %lu\n", 337 EFI_ERROR_CODE(status)); 338 339 loaded_image->DeviceHandle = bootdevhandle; 340 341 status = systab->BootServices->StartImage(loaderhandle, NULL, NULL); 342 if (EFI_ERROR(status)) 343 printf("StartImage failed with error %lu\n", 344 EFI_ERROR_CODE(status)); 345} 346 347static void 348panic(const char *fmt, ...) 349{ 350 char buf[128]; 351 va_list ap; 352 353 va_start(ap, fmt); 354 vsnprintf(buf, sizeof buf, fmt, ap); 355 printf("panic: %s\n", buf); 356 va_end(ap); 357 358 while (1) {} 359} 360 361static int 362printf(const char *fmt, ...) 363{ 364 va_list ap; 365 int ret; 366 367 /* Don't annoy the user as we probe for partitions */ 368 if (strcmp(fmt,"Not ufs\n") == 0) 369 return 0; 370 371 va_start(ap, fmt); 372 ret = vprintf(fmt, ap); 373 va_end(ap); 374 return (ret); 375} 376 377static int 378putchar(char c, void *arg) 379{ 380 CHAR16 buf[2]; 381 382 if (c == '\n') { 383 buf[0] = '\r'; 384 buf[1] = 0; 385 systab->ConOut->OutputString(systab->ConOut, buf); 386 } 387 buf[0] = c; 388 buf[1] = 0; 389 systab->ConOut->OutputString(systab->ConOut, buf); 390 return (1); 391} 392 393static int 394vprintf(const char *fmt, va_list ap) 395{ 396 int ret; 397 398 ret = __printf(fmt, putchar, 0, ap); 399 return (ret); 400} 401 402static int 403vsnprintf(char *str, size_t sz, const char *fmt, va_list ap) 404{ 405 struct sp_data sp; 406 int ret; 407 408 sp.sp_buf = str; 409 sp.sp_len = 0; 410 sp.sp_size = sz; 411 ret = __printf(fmt, __sputc, &sp, ap); 412 return (ret); 413} 414 415static int 416__printf(const char *fmt, putc_func_t *putc, void *arg, va_list ap) 417{ 418 char buf[(sizeof(long) * 8) + 1]; 419 char *nbuf; 420 u_long ul; 421 u_int ui; 422 int lflag; 423 int sflag; 424 char *s; 425 int pad; 426 int ret; 427 int c; 428 429 nbuf = &buf[sizeof buf - 1]; 430 ret = 0; 431 while ((c = *fmt++) != 0) { 432 if (c != '%') { 433 ret += putc(c, arg); 434 continue; 435 } 436 lflag = 0; 437 sflag = 0; 438 pad = 0; 439reswitch: c = *fmt++; 440 switch (c) { 441 case '#': 442 sflag = 1; 443 goto reswitch; 444 case '%': 445 ret += putc('%', arg); 446 break; 447 case 'c': 448 c = va_arg(ap, int); 449 ret += putc(c, arg); 450 break; 451 case 'd': 452 if (lflag == 0) { 453 ui = (u_int)va_arg(ap, int); 454 if (ui < (int)ui) { 455 ui = -ui; 456 ret += putc('-', arg); 457 } 458 s = __uitoa(nbuf, ui, 10); 459 } else { 460 ul = (u_long)va_arg(ap, long); 461 if (ul < (long)ul) { 462 ul = -ul; 463 ret += putc('-', arg); 464 } 465 s = __ultoa(nbuf, ul, 10); 466 } 467 ret += __puts(s, putc, arg); 468 break; 469 case 'l': 470 lflag = 1; 471 goto reswitch; 472 case 'o': 473 if (lflag == 0) { 474 ui = (u_int)va_arg(ap, u_int); 475 s = __uitoa(nbuf, ui, 8); 476 } else { 477 ul = (u_long)va_arg(ap, u_long); 478 s = __ultoa(nbuf, ul, 8); 479 } 480 ret += __puts(s, putc, arg); 481 break; 482 case 'p': 483 ul = (u_long)va_arg(ap, void *); 484 s = __ultoa(nbuf, ul, 16); 485 ret += __puts("0x", putc, arg); 486 ret += __puts(s, putc, arg); 487 break; 488 case 's': 489 s = va_arg(ap, char *); 490 ret += __puts(s, putc, arg); 491 break; 492 case 'u': 493 if (lflag == 0) { 494 ui = va_arg(ap, u_int); 495 s = __uitoa(nbuf, ui, 10); 496 } else { 497 ul = va_arg(ap, u_long); 498 s = __ultoa(nbuf, ul, 10); 499 } 500 ret += __puts(s, putc, arg); 501 break; 502 case 'x': 503 if (lflag == 0) { 504 ui = va_arg(ap, u_int); 505 s = __uitoa(nbuf, ui, 16); 506 } else { 507 ul = va_arg(ap, u_long); 508 s = __ultoa(nbuf, ul, 16); 509 } 510 if (sflag) 511 ret += __puts("0x", putc, arg); 512 ret += __puts(s, putc, arg); 513 break; 514 case '0': case '1': case '2': case '3': case '4': 515 case '5': case '6': case '7': case '8': case '9': 516 pad = pad * 10 + c - '0'; 517 goto reswitch; 518 default: 519 break; 520 } 521 } 522 return (ret); 523} 524 525static int 526__sputc(char c, void *arg) 527{ 528 struct sp_data *sp; 529 530 sp = arg; 531 if (sp->sp_len < sp->sp_size) 532 sp->sp_buf[sp->sp_len++] = c; 533 sp->sp_buf[sp->sp_len] = '\0'; 534 return (1); 535} 536 537static int 538__puts(const char *s, putc_func_t *putc, void *arg) 539{ 540 const char *p; 541 int ret; 542 543 ret = 0; 544 for (p = s; *p != '\0'; p++) 545 ret += putc(*p, arg); 546 return (ret); 547} 548 549static char * 550__uitoa(char *buf, u_int ui, int base) 551{ 552 char *p; 553 554 p = buf; 555 *p = '\0'; 556 do 557 *--p = digits[ui % base]; 558 while ((ui /= base) != 0); 559 return (p); 560} 561 562static char * 563__ultoa(char *buf, u_long ul, int base) 564{ 565 char *p; 566 567 p = buf; 568 *p = '\0'; 569 do 570 *--p = digits[ul % base]; 571 while ((ul /= base) != 0); 572 return (p); 573} 574