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