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