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