]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - stand/efi/boot1/boot1.c
loader.efi: efipart needs to use ioalign
[FreeBSD/FreeBSD.git] / stand / 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  * Copyright (c) 2015 Eric McCorkle
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms are freely
12  * permitted provided that the above copyright notice and this
13  * paragraph and the following disclaimer are duplicated in all
14  * such forms.
15  *
16  * This software is provided "AS IS" and without any express or
17  * implied warranties, including, without limitation, the implied
18  * warranties of merchantability and fitness for a particular
19  * purpose.
20  */
21
22 #include <sys/cdefs.h>
23 __FBSDID("$FreeBSD$");
24
25 #include <sys/param.h>
26 #include <machine/elf.h>
27 #include <machine/stdarg.h>
28 #include <stand.h>
29
30 #include <efi.h>
31 #include <eficonsctl.h>
32 #include <efichar.h>
33
34 #include "boot_module.h"
35 #include "paths.h"
36
37 static void efi_panic(EFI_STATUS s, const char *fmt, ...) __dead2 __printflike(2, 3);
38
39 static const boot_module_t *boot_modules[] =
40 {
41 #ifdef EFI_ZFS_BOOT
42         &zfs_module,
43 #endif
44 #ifdef EFI_UFS_BOOT
45         &ufs_module
46 #endif
47 };
48
49 #define NUM_BOOT_MODULES        nitems(boot_modules)
50 /* The initial number of handles used to query EFI for partitions. */
51 #define NUM_HANDLES_INIT        24
52
53 static EFI_GUID BlockIoProtocolGUID = BLOCK_IO_PROTOCOL;
54 static EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL;
55 static EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL;
56 static EFI_GUID ConsoleControlGUID = EFI_CONSOLE_CONTROL_PROTOCOL_GUID;
57
58 /*
59  * Provide Malloc / Free / Calloc backed by EFIs AllocatePool / FreePool which ensures
60  * memory is correctly aligned avoiding EFI_INVALID_PARAMETER returns from
61  * EFI methods.
62  */
63
64 void *
65 Malloc(size_t len, const char *file __unused, int line __unused)
66 {
67         void *out;
68
69         if (BS->AllocatePool(EfiLoaderData, len, &out) == EFI_SUCCESS)
70                 return (out);
71
72         return (NULL);
73 }
74
75 void
76 Free(void *buf, const char *file __unused, int line __unused)
77 {
78         if (buf != NULL)
79                 (void)BS->FreePool(buf);
80 }
81
82 void *
83 Calloc(size_t n1, size_t n2, const char *file, int line)
84 {
85         size_t bytes;
86         void *res;
87
88         bytes = n1 * n2;
89         if ((res = Malloc(bytes, file, line)) != NULL)
90                 bzero(res, bytes);
91
92         return (res);
93 }
94
95 /*
96  * nodes_match returns TRUE if the imgpath isn't NULL and the nodes match,
97  * FALSE otherwise.
98  */
99 static BOOLEAN
100 nodes_match(EFI_DEVICE_PATH *imgpath, EFI_DEVICE_PATH *devpath)
101 {
102         size_t len;
103
104         if (imgpath == NULL || imgpath->Type != devpath->Type ||
105             imgpath->SubType != devpath->SubType)
106                 return (FALSE);
107
108         len = DevicePathNodeLength(imgpath);
109         if (len != DevicePathNodeLength(devpath))
110                 return (FALSE);
111
112         return (memcmp(imgpath, devpath, (size_t)len) == 0);
113 }
114
115 /*
116  * device_paths_match returns TRUE if the imgpath isn't NULL and all nodes
117  * in imgpath and devpath match up to their respective occurrences of a
118  * media node, FALSE otherwise.
119  */
120 static BOOLEAN
121 device_paths_match(EFI_DEVICE_PATH *imgpath, EFI_DEVICE_PATH *devpath)
122 {
123
124         if (imgpath == NULL)
125                 return (FALSE);
126
127         while (!IsDevicePathEnd(imgpath) && !IsDevicePathEnd(devpath)) {
128                 if (IsDevicePathType(imgpath, MEDIA_DEVICE_PATH) &&
129                     IsDevicePathType(devpath, MEDIA_DEVICE_PATH))
130                         return (TRUE);
131
132                 if (!nodes_match(imgpath, devpath))
133                         return (FALSE);
134
135                 imgpath = NextDevicePathNode(imgpath);
136                 devpath = NextDevicePathNode(devpath);
137         }
138
139         return (FALSE);
140 }
141
142 /*
143  * devpath_last returns the last non-path end node in devpath.
144  */
145 static EFI_DEVICE_PATH *
146 devpath_last(EFI_DEVICE_PATH *devpath)
147 {
148
149         while (!IsDevicePathEnd(NextDevicePathNode(devpath)))
150                 devpath = NextDevicePathNode(devpath);
151
152         return (devpath);
153 }
154
155 /*
156  * load_loader attempts to load the loader image data.
157  *
158  * It tries each module and its respective devices, identified by mod->probe,
159  * in order until a successful load occurs at which point it returns EFI_SUCCESS
160  * and EFI_NOT_FOUND otherwise.
161  *
162  * Only devices which have preferred matching the preferred parameter are tried.
163  */
164 static EFI_STATUS
165 load_loader(const boot_module_t **modp, dev_info_t **devinfop, void **bufp,
166     size_t *bufsize, BOOLEAN preferred)
167 {
168         UINTN i;
169         dev_info_t *dev;
170         const boot_module_t *mod;
171
172         for (i = 0; i < NUM_BOOT_MODULES; i++) {
173                 mod = boot_modules[i];
174                 for (dev = mod->devices(); dev != NULL; dev = dev->next) {
175                         if (dev->preferred != preferred)
176                                 continue;
177
178                         if (mod->load(PATH_LOADER_EFI, dev, bufp, bufsize) ==
179                             EFI_SUCCESS) {
180                                 *devinfop = dev;
181                                 *modp = mod;
182                                 return (EFI_SUCCESS);
183                         }
184                 }
185         }
186
187         return (EFI_NOT_FOUND);
188 }
189
190 /*
191  * try_boot only returns if it fails to load the loader. If it succeeds
192  * it simply boots, otherwise it returns the status of last EFI call.
193  */
194 static EFI_STATUS
195 try_boot(void)
196 {
197         size_t bufsize, loadersize, cmdsize;
198         void *buf, *loaderbuf;
199         char *cmd;
200         dev_info_t *dev;
201         const boot_module_t *mod;
202         EFI_HANDLE loaderhandle;
203         EFI_LOADED_IMAGE *loaded_image;
204         EFI_STATUS status;
205
206         status = load_loader(&mod, &dev, &loaderbuf, &loadersize, TRUE);
207         if (status != EFI_SUCCESS) {
208                 status = load_loader(&mod, &dev, &loaderbuf, &loadersize,
209                     FALSE);
210                 if (status != EFI_SUCCESS) {
211                         printf("Failed to load '%s'\n", PATH_LOADER_EFI);
212                         return (status);
213                 }
214         }
215
216         /*
217          * Read in and parse the command line from /boot.config or /boot/config,
218          * if present. We'll pass it the next stage via a simple ASCII
219          * string. loader.efi has a hack for ASCII strings, so we'll use that to
220          * keep the size down here. We only try to read the alternate file if
221          * we get EFI_NOT_FOUND because all other errors mean that the boot_module
222          * had troubles with the filesystem. We could return early, but we'll let
223          * loading the actual kernel sort all that out. Since these files are
224          * optional, we don't report errors in trying to read them.
225          */
226         cmd = NULL;
227         cmdsize = 0;
228         status = mod->load(PATH_DOTCONFIG, dev, &buf, &bufsize);
229         if (status == EFI_NOT_FOUND)
230                 status = mod->load(PATH_CONFIG, dev, &buf, &bufsize);
231         if (status == EFI_SUCCESS) {
232                 cmdsize = bufsize + 1;
233                 cmd = malloc(cmdsize);
234                 if (cmd == NULL)
235                         goto errout;
236                 memcpy(cmd, buf, bufsize);
237                 cmd[bufsize] = '\0';
238                 free(buf);
239                 buf = NULL;
240         }
241
242         if ((status = BS->LoadImage(TRUE, IH, devpath_last(dev->devpath),
243             loaderbuf, loadersize, &loaderhandle)) != EFI_SUCCESS) {
244                 printf("Failed to load image provided by %s, size: %zu, (%lu)\n",
245                      mod->name, loadersize, EFI_ERROR_CODE(status));
246                 goto errout;
247         }
248
249         status = OpenProtocolByHandle(loaderhandle, &LoadedImageGUID,
250             (void **)&loaded_image);
251         if (status != EFI_SUCCESS) {
252                 printf("Failed to query LoadedImage provided by %s (%lu)\n",
253                     mod->name, EFI_ERROR_CODE(status));
254                 goto errout;
255         }
256
257         if (cmd != NULL)
258                 printf("    command args: %s\n", cmd);
259
260         loaded_image->DeviceHandle = dev->devhandle;
261         loaded_image->LoadOptionsSize = cmdsize;
262         loaded_image->LoadOptions = cmd;
263
264         DPRINTF("Starting '%s' in 5 seconds...", PATH_LOADER_EFI);
265         DSTALL(1000000);
266         DPRINTF(".");
267         DSTALL(1000000);
268         DPRINTF(".");
269         DSTALL(1000000);
270         DPRINTF(".");
271         DSTALL(1000000);
272         DPRINTF(".");
273         DSTALL(1000000);
274         DPRINTF(".\n");
275
276         if ((status = BS->StartImage(loaderhandle, NULL, NULL)) !=
277             EFI_SUCCESS) {
278                 printf("Failed to start image provided by %s (%lu)\n",
279                     mod->name, EFI_ERROR_CODE(status));
280                 loaded_image->LoadOptionsSize = 0;
281                 loaded_image->LoadOptions = NULL;
282         }
283
284 errout:
285         if (cmd != NULL)
286                 free(cmd);
287         if (buf != NULL)
288                 free(buf);
289         if (loaderbuf != NULL)
290                 free(loaderbuf);
291
292         return (status);
293 }
294
295 /*
296  * probe_handle determines if the passed handle represents a logical partition
297  * if it does it uses each module in order to probe it and if successful it
298  * returns EFI_SUCCESS.
299  */
300 static EFI_STATUS
301 probe_handle(EFI_HANDLE h, EFI_DEVICE_PATH *imgpath, BOOLEAN *preferred)
302 {
303         dev_info_t *devinfo;
304         EFI_BLOCK_IO *blkio;
305         EFI_DEVICE_PATH *devpath;
306         EFI_STATUS status;
307         UINTN i;
308
309         /* Figure out if we're dealing with an actual partition. */
310         status = OpenProtocolByHandle(h, &DevicePathGUID, (void **)&devpath);
311         if (status == EFI_UNSUPPORTED)
312                 return (status);
313
314         if (status != EFI_SUCCESS) {
315                 DPRINTF("\nFailed to query DevicePath (%lu)\n",
316                     EFI_ERROR_CODE(status));
317                 return (status);
318         }
319 #ifdef EFI_DEBUG
320         {
321                 CHAR16 *text = efi_devpath_name(devpath);
322                 DPRINTF("probing: %S\n", text);
323                 efi_free_devpath_name(text);
324         }
325 #endif
326         status = OpenProtocolByHandle(h, &BlockIoProtocolGUID, (void **)&blkio);
327         if (status == EFI_UNSUPPORTED)
328                 return (status);
329
330         if (status != EFI_SUCCESS) {
331                 DPRINTF("\nFailed to query BlockIoProtocol (%lu)\n",
332                     EFI_ERROR_CODE(status));
333                 return (status);
334         }
335
336         if (!blkio->Media->LogicalPartition)
337                 return (EFI_UNSUPPORTED);
338
339         *preferred = device_paths_match(imgpath, devpath);
340
341         /* Run through each module, see if it can load this partition */
342         for (i = 0; i < NUM_BOOT_MODULES; i++) {
343                 devinfo = malloc(sizeof(*devinfo));
344                 if (devinfo == NULL) {
345                         DPRINTF("\nFailed to allocate devinfo\n");
346                         continue;
347                 }
348                 devinfo->dev = blkio;
349                 devinfo->devpath = devpath;
350                 devinfo->devhandle = h;
351                 devinfo->devdata = NULL;
352                 devinfo->preferred = *preferred;
353                 devinfo->next = NULL;
354
355                 status = boot_modules[i]->probe(devinfo);
356                 if (status == EFI_SUCCESS)
357                         return (EFI_SUCCESS);
358                 free(devinfo);
359         }
360
361         return (EFI_UNSUPPORTED);
362 }
363
364 /*
365  * probe_handle_status calls probe_handle and outputs the returned status
366  * of the call.
367  */
368 static void
369 probe_handle_status(EFI_HANDLE h, EFI_DEVICE_PATH *imgpath)
370 {
371         EFI_STATUS status;
372         BOOLEAN preferred;
373
374         preferred = FALSE;
375         status = probe_handle(h, imgpath, &preferred);
376         
377         DPRINTF("probe: ");
378         switch (status) {
379         case EFI_UNSUPPORTED:
380                 printf(".");
381                 DPRINTF(" not supported\n");
382                 break;
383         case EFI_SUCCESS:
384                 if (preferred) {
385                         printf("%c", '*');
386                         DPRINTF(" supported (preferred)\n");
387                 } else {
388                         printf("%c", '+');
389                         DPRINTF(" supported\n");
390                 }
391                 break;
392         default:
393                 printf("x");
394                 DPRINTF(" error (%lu)\n", EFI_ERROR_CODE(status));
395                 break;
396         }
397         DSTALL(500000);
398 }
399
400 EFI_STATUS
401 efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE *Xsystab)
402 {
403         EFI_HANDLE *handles;
404         EFI_LOADED_IMAGE *img;
405         EFI_DEVICE_PATH *imgpath;
406         EFI_STATUS status;
407         EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl = NULL;
408         SIMPLE_TEXT_OUTPUT_INTERFACE *conout = NULL;
409         UINTN i, hsize, nhandles;
410         CHAR16 *text;
411         UINT16 boot_current;
412         size_t sz;
413         UINT16 boot_order[100];
414
415         /* Basic initialization*/
416         ST = Xsystab;
417         IH = Ximage;
418         BS = ST->BootServices;
419         RS = ST->RuntimeServices;
420
421         /* Set up the console, so printf works. */
422         status = BS->LocateProtocol(&ConsoleControlGUID, NULL,
423             (VOID **)&ConsoleControl);
424         if (status == EFI_SUCCESS)
425                 (void)ConsoleControl->SetMode(ConsoleControl,
426                     EfiConsoleControlScreenText);
427         /*
428          * Reset the console enable the cursor. Later we'll choose a better
429          * console size through GOP/UGA.
430          */
431         conout = ST->ConOut;
432         conout->Reset(conout, TRUE);
433         /* Explicitly set conout to mode 0, 80x25 */
434         conout->SetMode(conout, 0);
435         conout->EnableCursor(conout, TRUE);
436         conout->ClearScreen(conout);
437
438         printf("\n>> FreeBSD EFI boot block\n");
439         printf("   Loader path: %s\n\n", PATH_LOADER_EFI);
440         printf("   Initializing modules:");
441         for (i = 0; i < NUM_BOOT_MODULES; i++) {
442                 printf(" %s", boot_modules[i]->name);
443                 if (boot_modules[i]->init != NULL)
444                         boot_modules[i]->init();
445         }
446         putchar('\n');
447
448         /* Determine the devpath of our image so we can prefer it. */
449         status = OpenProtocolByHandle(IH, &LoadedImageGUID, (void **)&img);
450         imgpath = NULL;
451         if (status == EFI_SUCCESS) {
452                 text = efi_devpath_name(img->FilePath);
453                 if (text != NULL) {
454                         printf("   Load Path: %S\n", text);
455                         efi_setenv_freebsd_wcs("Boot1Path", text);
456                         efi_free_devpath_name(text);
457                 }
458
459                 status = OpenProtocolByHandle(img->DeviceHandle,
460                     &DevicePathGUID, (void **)&imgpath);
461                 if (status != EFI_SUCCESS) {
462                         DPRINTF("Failed to get image DevicePath (%lu)\n",
463                             EFI_ERROR_CODE(status));
464                 } else {
465                         text = efi_devpath_name(imgpath);
466                         if (text != NULL) {
467                                 printf("   Load Device: %S\n", text);
468                                 efi_setenv_freebsd_wcs("Boot1Dev", text);
469                                 efi_free_devpath_name(text);
470                         }
471                 }
472         }
473
474         boot_current = 0;
475         sz = sizeof(boot_current);
476         if (efi_global_getenv("BootCurrent", &boot_current, &sz) == EFI_SUCCESS) {
477                 printf("   BootCurrent: %04x\n", boot_current);
478
479                 sz = sizeof(boot_order);
480                 if (efi_global_getenv("BootOrder", &boot_order, &sz) == EFI_SUCCESS) {
481                         printf("   BootOrder:");
482                         for (i = 0; i < sz / sizeof(boot_order[0]); i++)
483                                 printf(" %04x%s", boot_order[i],
484                                     boot_order[i] == boot_current ? "[*]" : "");
485                         printf("\n");
486                 }
487         }
488
489 #ifdef TEST_FAILURE
490         /*
491          * For testing failover scenarios, it's nice to be able to fail fast.
492          * Define TEST_FAILURE to create a boot1.efi that always fails after
493          * reporting the boot manager protocol details.
494          */
495         BS->Exit(IH, EFI_OUT_OF_RESOURCES, 0, NULL);
496 #endif
497
498         /* Get all the device handles */
499         hsize = (UINTN)NUM_HANDLES_INIT * sizeof(EFI_HANDLE);
500         handles = malloc(hsize);
501         if (handles == NULL)
502                 printf("Failed to allocate %d handles\n", NUM_HANDLES_INIT);
503
504         status = BS->LocateHandle(ByProtocol, &BlockIoProtocolGUID, NULL,
505             &hsize, handles);
506         switch (status) {
507         case EFI_SUCCESS:
508                 break;
509         case EFI_BUFFER_TOO_SMALL:
510                 free(handles);
511                 handles = malloc(hsize);
512                 if (handles == NULL)
513                         efi_panic(EFI_OUT_OF_RESOURCES, "Failed to allocate %d handles\n",
514                             NUM_HANDLES_INIT);
515                 status = BS->LocateHandle(ByProtocol, &BlockIoProtocolGUID,
516                     NULL, &hsize, handles);
517                 if (status != EFI_SUCCESS)
518                         efi_panic(status, "Failed to get device handles\n");
519                 break;
520         default:
521                 efi_panic(status, "Failed to get device handles\n");
522                 break;
523         }
524
525         /* Scan all partitions, probing with all modules. */
526         nhandles = hsize / sizeof(*handles);
527         printf("   Probing %zu block devices...", nhandles);
528         DPRINTF("\n");
529
530         for (i = 0; i < nhandles; i++)
531                 probe_handle_status(handles[i], imgpath);
532         printf(" done\n");
533
534         /* Status summary. */
535         for (i = 0; i < NUM_BOOT_MODULES; i++) {
536                 printf("    ");
537                 boot_modules[i]->status();
538         }
539
540         try_boot();
541
542         /* If we get here, we're out of luck... */
543         efi_panic(EFI_LOAD_ERROR, "No bootable partitions found!");
544 }
545
546 /*
547  * add_device adds a device to the passed devinfo list.
548  */
549 void
550 add_device(dev_info_t **devinfop, dev_info_t *devinfo)
551 {
552         dev_info_t *dev;
553
554         if (*devinfop == NULL) {
555                 *devinfop = devinfo;
556                 return;
557         }
558
559         for (dev = *devinfop; dev->next != NULL; dev = dev->next)
560                 ;
561
562         dev->next = devinfo;
563 }
564
565 /*
566  * OK. We totally give up. Exit back to EFI with a sensible status so
567  * it can try the next option on the list.
568  */
569 static void
570 efi_panic(EFI_STATUS s, const char *fmt, ...)
571 {
572         va_list ap;
573
574         printf("panic: ");
575         va_start(ap, fmt);
576         vprintf(fmt, ap);
577         va_end(ap);
578         printf("\n");
579
580         BS->Exit(IH, s, 0, NULL);
581 }
582
583 void
584 putchar(int c)
585 {
586         CHAR16 buf[2];
587
588         if (c == '\n') {
589                 buf[0] = '\r';
590                 buf[1] = 0;
591                 ST->ConOut->OutputString(ST->ConOut, buf);
592         }
593         buf[0] = c;
594         buf[1] = 0;
595         ST->ConOut->OutputString(ST->ConOut, buf);
596 }