]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - sys/boot/efi/boot1/boot1.c
MFC r281059 (by rpaulo):
[FreeBSD/stable/10.git] / sys / boot / efi / boot1 / boot1.c
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$");
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
36 typedef int putc_func_t(char c, void *arg);
37
38 struct sp_data {
39         char    *sp_buf;
40         u_int   sp_len;
41         u_int   sp_size;
42 };
43
44 static const char digits[] = "0123456789abcdef";
45
46 static void panic(const char *fmt, ...) __dead2;
47 static int printf(const char *fmt, ...);
48 static int putchar(char c, void *arg);
49 static int vprintf(const char *fmt, va_list ap);
50 static int vsnprintf(char *str, size_t sz, const char *fmt, va_list ap);
51
52 static int __printf(const char *fmt, putc_func_t *putc, void *arg, va_list ap);
53 static int __putc(char c, void *arg);
54 static int __puts(const char *s, putc_func_t *putc, void *arg);
55 static int __sputc(char c, void *arg);
56 static char *__uitoa(char *buf, u_int val, int base);
57 static char *__ultoa(char *buf, u_long val, int base);
58
59 static int domount(EFI_DEVICE_PATH *device, EFI_BLOCK_IO *blkio, int quiet);
60 static void load(const char *fname);
61
62 EFI_SYSTEM_TABLE *systab;
63 EFI_HANDLE *image;
64
65 static void
66 bcopy(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
75 static void
76 memcpy(void *dst, const void *src, size_t len)
77 {
78         bcopy(src, dst, len);
79 }
80
81 static void
82 bzero(void *b, size_t len)
83 {
84         char *p = b;
85
86         while (len-- != 0)
87                 *p++ = 0;
88 }
89
90 static int
91 strcmp(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
98 static EFI_GUID BlockIoProtocolGUID = BLOCK_IO_PROTOCOL;
99 static EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL;
100 static EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL;
101 static EFI_GUID ConsoleControlGUID = EFI_CONSOLE_CONTROL_PROTOCOL_GUID;
102
103 static EFI_BLOCK_IO *bootdev;
104 static EFI_DEVICE_PATH *bootdevpath;
105 static EFI_HANDLE *bootdevhandle;
106
107 EFI_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>> 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
188 static int
189 dskread(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
207 static ssize_t
208 fsstat(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
289 static struct dmadat __dmadat;
290
291 static int
292 domount(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
308 static void
309 load(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
349 static void
350 panic(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
363 static int
364 printf(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
379 static int
380 putchar(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
395 static int
396 vprintf(const char *fmt, va_list ap)
397 {
398         int ret;
399
400         ret = __printf(fmt, putchar, 0, ap);
401         return (ret);
402 }
403
404 static int
405 vsnprintf(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
417 static 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;
441 reswitch:       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
527 static 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
539 static 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
551 static 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
564 static 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 }