]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/boot/efi/boot1/boot1.c
Update from svn-1.8.14 to 1.9.2.
[FreeBSD/FreeBSD.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 static EFI_SYSTEM_TABLE *systab;
63 static 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"
150                ">> FreeBSD EFI boot block\n");
151         printf("   Loader path: %s\n", path);
152
153         status = systab->BootServices->LocateHandle(ByProtocol,
154             &BlockIoProtocolGUID, NULL, &nparts, handles);
155         nparts /= sizeof(handles[0]);
156
157         for (i = 0; i < nparts; i++) {
158                 status = systab->BootServices->HandleProtocol(handles[i],
159                     &DevicePathGUID, (void **)&devpath);
160                 if (EFI_ERROR(status))
161                         continue;
162
163                 while (!IsDevicePathEnd(NextDevicePathNode(devpath)))
164                         devpath = NextDevicePathNode(devpath);
165
166                 status = systab->BootServices->HandleProtocol(handles[i],
167                     &BlockIoProtocolGUID, (void **)&blkio);
168                 if (EFI_ERROR(status))
169                         continue;
170
171                 if (!blkio->Media->LogicalPartition)
172                         continue;
173
174                 if (domount(devpath, blkio, 1) >= 0)
175                         break;
176         }
177
178         if (i == nparts)
179                 panic("No bootable partition found");
180
181         bootdevhandle = handles[i];
182         load(path);
183
184         panic("Load failed");
185
186         return EFI_SUCCESS;
187 }
188
189 static int
190 dskread(void *buf, u_int64_t lba, int nblk)
191 {
192         EFI_STATUS status;
193         int size;
194
195         lba = lba / (bootdev->Media->BlockSize / DEV_BSIZE);
196         size = nblk * DEV_BSIZE;
197         status = bootdev->ReadBlocks(bootdev, bootdev->Media->MediaId, lba,
198             size, buf);
199
200         if (EFI_ERROR(status))
201                 return (-1);
202
203         return (0);
204 }
205
206 #include "ufsread.c"
207
208 static ssize_t
209 fsstat(ufs_ino_t inode)
210 {
211 #ifndef UFS2_ONLY
212         static struct ufs1_dinode dp1;
213         ufs1_daddr_t addr1;
214 #endif
215 #ifndef UFS1_ONLY
216         static struct ufs2_dinode dp2;
217 #endif
218         static struct fs fs;
219         static ufs_ino_t inomap;
220         char *blkbuf;
221         void *indbuf;
222         size_t n, nb, size, off, vboff;
223         ufs_lbn_t lbn;
224         ufs2_daddr_t addr2, vbaddr;
225         static ufs2_daddr_t blkmap, indmap;
226         u_int u;
227
228         blkbuf = dmadat->blkbuf;
229         indbuf = dmadat->indbuf;
230         if (!dsk_meta) {
231                 inomap = 0;
232                 for (n = 0; sblock_try[n] != -1; n++) {
233                         if (dskread(dmadat->sbbuf, sblock_try[n] / DEV_BSIZE,
234                             SBLOCKSIZE / DEV_BSIZE))
235                                 return -1;
236                         memcpy(&fs, dmadat->sbbuf, sizeof(struct fs));
237                         if ((
238 #if defined(UFS1_ONLY)
239                             fs.fs_magic == FS_UFS1_MAGIC
240 #elif defined(UFS2_ONLY)
241                             (fs.fs_magic == FS_UFS2_MAGIC &&
242                             fs.fs_sblockloc == sblock_try[n])
243 #else
244                             fs.fs_magic == FS_UFS1_MAGIC ||
245                             (fs.fs_magic == FS_UFS2_MAGIC &&
246                             fs.fs_sblockloc == sblock_try[n])
247 #endif
248                             ) &&
249                             fs.fs_bsize <= MAXBSIZE &&
250                             fs.fs_bsize >= sizeof(struct fs))
251                                 break;
252                 }
253                 if (sblock_try[n] == -1) {
254                         printf("Not ufs\n");
255                         return -1;
256                 }
257                 dsk_meta++;
258         } else
259                 memcpy(&fs, dmadat->sbbuf, sizeof(struct fs));
260         if (!inode)
261                 return 0;
262         if (inomap != inode) {
263                 n = IPERVBLK(&fs);
264                 if (dskread(blkbuf, INO_TO_VBA(&fs, n, inode), DBPERVBLK))
265                         return -1;
266                 n = INO_TO_VBO(n, inode);
267 #if defined(UFS1_ONLY)
268                 memcpy(&dp1, (struct ufs1_dinode *)blkbuf + n,
269                     sizeof(struct ufs1_dinode));
270 #elif defined(UFS2_ONLY)
271                 memcpy(&dp2, (struct ufs2_dinode *)blkbuf + n,
272                     sizeof(struct ufs2_dinode));
273 #else
274                 if (fs.fs_magic == FS_UFS1_MAGIC)
275                         memcpy(&dp1, (struct ufs1_dinode *)blkbuf + n,
276                             sizeof(struct ufs1_dinode));
277                 else
278                         memcpy(&dp2, (struct ufs2_dinode *)blkbuf + n,
279                             sizeof(struct ufs2_dinode));
280 #endif
281                 inomap = inode;
282                 fs_off = 0;
283                 blkmap = indmap = 0;
284         }
285         size = DIP(di_size);
286         n = size - fs_off;
287         return (n);
288 }
289
290 static struct dmadat __dmadat;
291
292 static int
293 domount(EFI_DEVICE_PATH *device, EFI_BLOCK_IO *blkio, int quiet)
294 {
295
296         dmadat = &__dmadat;
297         bootdev = blkio;
298         bootdevpath = device;
299         if (fsread(0, NULL, 0)) {
300                 if (!quiet)
301                         printf("domount: can't read superblock\n");
302                 return (-1);
303         }
304         if (!quiet)
305                 printf("Succesfully mounted UFS filesystem\n");
306         return (0);
307 }
308
309 static void
310 load(const char *fname)
311 {
312         ufs_ino_t ino;
313         EFI_STATUS status;
314         EFI_HANDLE loaderhandle;
315         EFI_LOADED_IMAGE *loaded_image;
316         void *buffer;
317         size_t bufsize;
318
319         if ((ino = lookup(fname)) == 0) {
320                 printf("File %s not found\n", fname);
321                 return;
322         }
323
324         bufsize = fsstat(ino);
325         status = systab->BootServices->AllocatePool(EfiLoaderData,
326             bufsize, &buffer);
327         fsread(ino, buffer, bufsize);
328
329         /* XXX: For secure boot, we need our own loader here */
330         status = systab->BootServices->LoadImage(TRUE, image, bootdevpath,
331             buffer, bufsize, &loaderhandle);
332         if (EFI_ERROR(status))
333                 printf("LoadImage failed with error %lx\n", status);
334
335         status = systab->BootServices->HandleProtocol(loaderhandle,
336             &LoadedImageGUID, (VOID**)&loaded_image);
337         if (EFI_ERROR(status))
338                 printf("HandleProtocol failed with error %lx\n", status);
339
340         loaded_image->DeviceHandle = bootdevhandle;
341
342         status = systab->BootServices->StartImage(loaderhandle, NULL, NULL);
343         if (EFI_ERROR(status))
344                 printf("StartImage failed with error %lx\n", 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 }