]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - sys/boot/amd64/boot1.efi/boot1.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / sys / boot / amd64 / boot1.efi / 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);
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
167 static int
168 dskread(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
186 static ssize_t
187 fsstat(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
268 static struct dmadat __dmadat;
269                 
270 static int
271 domount(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
287 static void
288 load(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
311         status = systab->BootServices->HandleProtocol(loaderhandle,
312             &LoadedImageGUID, (VOID**)&loaded_image);
313         loaded_image->DeviceHandle = bootdevhandle;
314
315         status = systab->BootServices->StartImage(loaderhandle, NULL, NULL);
316 }
317
318 static void
319 panic(const char *fmt, ...)
320 {
321         char buf[128];
322         va_list ap;
323
324         va_start(ap, fmt);
325         vsnprintf(buf, sizeof buf, fmt, ap);
326         printf("panic: %s\n", buf);
327         va_end(ap);
328
329         while (1) {}
330 }
331
332 static int
333 printf(const char *fmt, ...)
334 {
335         va_list ap;
336         int ret;
337
338         /* Don't annoy the user as we probe for partitions */
339         if (strcmp(fmt,"Not ufs\n") == 0)
340                 return 0;
341
342         va_start(ap, fmt);
343         ret = vprintf(fmt, ap);
344         va_end(ap);
345         return (ret);
346 }
347
348 static int
349 putchar(char c, void *arg)
350 {
351         CHAR16 buf[2];
352
353         if (c == '\n') {
354                 buf[0] = '\r';
355                 buf[1] = 0;
356                 systab->ConOut->OutputString(systab->ConOut, buf);
357         }
358         buf[0] = c;
359         buf[1] = 0;
360         systab->ConOut->OutputString(systab->ConOut, buf);
361         return (1);
362 }
363
364 static int
365 vprintf(const char *fmt, va_list ap)
366 {
367         int ret;
368
369         ret = __printf(fmt, putchar, 0, ap);
370         return (ret);
371 }
372
373 static int
374 vsnprintf(char *str, size_t sz, const char *fmt, va_list ap)
375 {
376         struct sp_data sp;
377         int ret;
378
379         sp.sp_buf = str;
380         sp.sp_len = 0;
381         sp.sp_size = sz;
382         ret = __printf(fmt, __sputc, &sp, ap);
383         return (ret);
384 }
385
386 static int
387 __printf(const char *fmt, putc_func_t *putc, void *arg, va_list ap)
388 {
389         char buf[(sizeof(long) * 8) + 1];
390         char *nbuf;
391         u_long ul;
392         u_int ui;
393         int lflag;
394         int sflag;
395         char *s;
396         int pad;
397         int ret;
398         int c;
399
400         nbuf = &buf[sizeof buf - 1];
401         ret = 0;
402         while ((c = *fmt++) != 0) {
403                 if (c != '%') {
404                         ret += putc(c, arg);
405                         continue;
406                 }
407                 lflag = 0;
408                 sflag = 0;
409                 pad = 0;
410 reswitch:       c = *fmt++;
411                 switch (c) {
412                 case '#':
413                         sflag = 1;
414                         goto reswitch;
415                 case '%':
416                         ret += putc('%', arg);
417                         break;
418                 case 'c':
419                         c = va_arg(ap, int);
420                         ret += putc(c, arg);
421                         break;
422                 case 'd':
423                         if (lflag == 0) {
424                                 ui = (u_int)va_arg(ap, int);
425                                 if (ui < (int)ui) {
426                                         ui = -ui;
427                                         ret += putc('-', arg);
428                                 }
429                                 s = __uitoa(nbuf, ui, 10);
430                         } else {
431                                 ul = (u_long)va_arg(ap, long);
432                                 if (ul < (long)ul) {
433                                         ul = -ul;
434                                         ret += putc('-', arg);
435                                 }
436                                 s = __ultoa(nbuf, ul, 10);
437                         }
438                         ret += __puts(s, putc, arg);
439                         break;
440                 case 'l':
441                         lflag = 1;
442                         goto reswitch;
443                 case 'o':
444                         if (lflag == 0) {
445                                 ui = (u_int)va_arg(ap, u_int);
446                                 s = __uitoa(nbuf, ui, 8);
447                         } else {
448                                 ul = (u_long)va_arg(ap, u_long);
449                                 s = __ultoa(nbuf, ul, 8);
450                         }
451                         ret += __puts(s, putc, arg);
452                         break;
453                 case 'p':
454                         ul = (u_long)va_arg(ap, void *);
455                         s = __ultoa(nbuf, ul, 16);
456                         ret += __puts("0x", putc, arg);
457                         ret += __puts(s, putc, arg);
458                         break;
459                 case 's':
460                         s = va_arg(ap, char *);
461                         ret += __puts(s, putc, arg);
462                         break;
463                 case 'u':
464                         if (lflag == 0) {
465                                 ui = va_arg(ap, u_int);
466                                 s = __uitoa(nbuf, ui, 10);
467                         } else {
468                                 ul = va_arg(ap, u_long);
469                                 s = __ultoa(nbuf, ul, 10);
470                         }
471                         ret += __puts(s, putc, arg);
472                         break;
473                 case 'x':
474                         if (lflag == 0) {
475                                 ui = va_arg(ap, u_int);
476                                 s = __uitoa(nbuf, ui, 16);
477                         } else {
478                                 ul = va_arg(ap, u_long);
479                                 s = __ultoa(nbuf, ul, 16);
480                         }
481                         if (sflag)
482                                 ret += __puts("0x", putc, arg);
483                         ret += __puts(s, putc, arg);
484                         break;
485                 case '0': case '1': case '2': case '3': case '4':
486                 case '5': case '6': case '7': case '8': case '9':
487                         pad = pad * 10 + c - '0';
488                         goto reswitch;
489                 default:
490                         break;
491                 }
492         }
493         return (ret);
494 }
495
496 static int
497 __sputc(char c, void *arg)
498 {
499         struct sp_data *sp;
500
501         sp = arg;
502         if (sp->sp_len < sp->sp_size)
503                 sp->sp_buf[sp->sp_len++] = c;
504         sp->sp_buf[sp->sp_len] = '\0';
505         return (1);
506 }
507
508 static int
509 __puts(const char *s, putc_func_t *putc, void *arg)
510 {
511         const char *p;
512         int ret;
513
514         ret = 0;
515         for (p = s; *p != '\0'; p++)
516                 ret += putc(*p, arg);
517         return (ret);
518 }
519
520 static char *
521 __uitoa(char *buf, u_int ui, int base)
522 {
523         char *p;
524
525         p = buf;
526         *p = '\0';
527         do
528                 *--p = digits[ui % base];
529         while ((ui /= base) != 0);
530         return (p);
531 }
532
533 static char *
534 __ultoa(char *buf, u_long ul, int base)
535 {
536         char *p;
537
538         p = buf;
539         *p = '\0';
540         do
541                 *--p = digits[ul % base];
542         while ((ul /= base) != 0);
543         return (p);
544 }
545