]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - sys/boot/efi/boot1/boot1.c
MFC r293461:
[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, &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
187 static int
188 dskread(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
206 static ssize_t
207 fsstat(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
287 static struct dmadat __dmadat;
288
289 static int
290 domount(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
306 static void
307 load(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
347 static void
348 panic(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
361 static int
362 printf(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
377 static int
378 putchar(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
393 static int
394 vprintf(const char *fmt, va_list ap)
395 {
396         int ret;
397
398         ret = __printf(fmt, putchar, 0, ap);
399         return (ret);
400 }
401
402 static int
403 vsnprintf(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
415 static 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;
439 reswitch:       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
525 static 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
537 static 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
549 static 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
562 static 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 }