]> CyberLeo.Net >> Repos - FreeBSD/releng/10.3.git/blob - sys/boot/efi/boot1/boot1.c
- Copy stable/10@296371 to releng/10.3 in preparation for 10.3-RC1
[FreeBSD/releng/10.3.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  * 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
33 #include "boot_module.h"
34 #include "paths.h"
35
36 static const boot_module_t *boot_modules[] =
37 {
38 #ifdef EFI_ZFS_BOOT
39         &zfs_module,
40 #endif
41 #ifdef EFI_UFS_BOOT
42         &ufs_module
43 #endif
44 };
45
46 #define NUM_BOOT_MODULES (sizeof(boot_modules) / sizeof(boot_module_t*))
47 /* The initial number of handles used to query EFI for partitions. */
48 #define NUM_HANDLES_INIT        24
49
50 void putchar(int c);
51 EFI_STATUS efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE* Xsystab);
52
53 EFI_SYSTEM_TABLE *systab;
54 EFI_BOOT_SERVICES *bs;
55 static EFI_HANDLE *image;
56
57 static EFI_GUID BlockIoProtocolGUID = BLOCK_IO_PROTOCOL;
58 static EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL;
59 static EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL;
60 static EFI_GUID ConsoleControlGUID = EFI_CONSOLE_CONTROL_PROTOCOL_GUID;
61
62 /*
63  * Provide Malloc / Free backed by EFIs AllocatePool / FreePool which ensures
64  * memory is correctly aligned avoiding EFI_INVALID_PARAMETER returns from
65  * EFI methods.
66  */
67 void *
68 Malloc(size_t len, const char *file __unused, int line __unused)
69 {
70         void *out;
71
72         if (bs->AllocatePool(EfiLoaderData, len, &out) == EFI_SUCCESS)
73                 return (out);
74
75         return (NULL);
76 }
77
78 void
79 Free(void *buf, const char *file __unused, int line __unused)
80 {
81         (void)bs->FreePool(buf);
82 }
83
84 /*
85  * nodes_match returns TRUE if the imgpath isn't NULL and the nodes match,
86  * FALSE otherwise.
87  */
88 static BOOLEAN
89 nodes_match(EFI_DEVICE_PATH *imgpath, EFI_DEVICE_PATH *devpath)
90 {
91         int len;
92
93         if (imgpath == NULL || imgpath->Type != devpath->Type ||
94             imgpath->SubType != devpath->SubType)
95                 return (FALSE);
96
97         len = DevicePathNodeLength(imgpath);
98         if (len != DevicePathNodeLength(devpath))
99                 return (FALSE);
100
101         return (memcmp(imgpath, devpath, (size_t)len) == 0);
102 }
103
104 /*
105  * device_paths_match returns TRUE if the imgpath isn't NULL and all nodes
106  * in imgpath and devpath match up to their respect occurances of a media
107  * node, FALSE otherwise.
108  */
109 static BOOLEAN
110 device_paths_match(EFI_DEVICE_PATH *imgpath, EFI_DEVICE_PATH *devpath)
111 {
112
113         if (imgpath == NULL)
114                 return (FALSE);
115
116         while (!IsDevicePathEnd(imgpath) && !IsDevicePathEnd(devpath)) {
117                 if (IsDevicePathType(imgpath, MEDIA_DEVICE_PATH) &&
118                     IsDevicePathType(devpath, MEDIA_DEVICE_PATH))
119                         return (TRUE);
120
121                 if (!nodes_match(imgpath, devpath))
122                         return (FALSE);
123
124                 imgpath = NextDevicePathNode(imgpath);
125                 devpath = NextDevicePathNode(devpath);
126         }
127
128         return (FALSE);
129 }
130
131 /*
132  * devpath_last returns the last non-path end node in devpath.
133  */
134 static EFI_DEVICE_PATH *
135 devpath_last(EFI_DEVICE_PATH *devpath)
136 {
137
138         while (!IsDevicePathEnd(NextDevicePathNode(devpath)))
139                 devpath = NextDevicePathNode(devpath);
140
141         return (devpath);
142 }
143
144 /*
145  * devpath_node_str is a basic output method for a devpath node which
146  * only understands a subset of the available sub types.
147  *
148  * If we switch to UEFI 2.x then we should update it to use:
149  * EFI_DEVICE_PATH_TO_TEXT_PROTOCOL.
150  */
151 static int
152 devpath_node_str(char *buf, size_t size, EFI_DEVICE_PATH *devpath)
153 {
154
155         switch (devpath->Type) {
156         case MESSAGING_DEVICE_PATH:
157                 switch (devpath->SubType) {
158                 case MSG_ATAPI_DP: {
159                         ATAPI_DEVICE_PATH *atapi;
160
161                         atapi = (ATAPI_DEVICE_PATH *)(void *)devpath;
162                         return snprintf(buf, size, "ata(%s,%s,0x%x)",
163                             (atapi->PrimarySecondary == 1) ?  "Sec" : "Pri",
164                             (atapi->SlaveMaster == 1) ?  "Slave" : "Master",
165                             atapi->Lun);
166                 }
167                 case MSG_USB_DP: {
168                         USB_DEVICE_PATH *usb;
169
170                         usb = (USB_DEVICE_PATH *)devpath;
171                         return snprintf(buf, size, "usb(0x%02x,0x%02x)",
172                             usb->ParentPortNumber, usb->InterfaceNumber);
173                 }
174                 case MSG_SCSI_DP: {
175                         SCSI_DEVICE_PATH *scsi;
176
177                         scsi = (SCSI_DEVICE_PATH *)(void *)devpath;
178                         return snprintf(buf, size, "scsi(0x%02x,0x%02x)",
179                             scsi->Pun, scsi->Lun);
180                 }
181                 case MSG_SATA_DP: {
182                         SATA_DEVICE_PATH *sata;
183
184                         sata = (SATA_DEVICE_PATH *)(void *)devpath;
185                         return snprintf(buf, size, "sata(0x%x,0x%x,0x%x)",
186                             sata->HBAPortNumber, sata->PortMultiplierPortNumber,
187                             sata->Lun);
188                 }
189                 default:
190                         return snprintf(buf, size, "msg(0x%02x)",
191                             devpath->SubType);
192                 }
193                 break;
194         case HARDWARE_DEVICE_PATH:
195                 switch (devpath->SubType) {
196                 case HW_PCI_DP: {
197                         PCI_DEVICE_PATH *pci;
198
199                         pci = (PCI_DEVICE_PATH *)devpath;
200                         return snprintf(buf, size, "pci(0x%02x,0x%02x)",
201                             pci->Device, pci->Function);
202                 }
203                 default:
204                         return snprintf(buf, size, "hw(0x%02x)",
205                             devpath->SubType);
206                 }
207                 break;
208         case ACPI_DEVICE_PATH: {
209                 ACPI_HID_DEVICE_PATH *acpi;
210
211                 acpi = (ACPI_HID_DEVICE_PATH *)(void *)devpath;
212                 if ((acpi->HID & PNP_EISA_ID_MASK) == PNP_EISA_ID_CONST) {
213                         switch (EISA_ID_TO_NUM(acpi->HID)) {
214                         case 0x0a03:
215                                 return snprintf(buf, size, "pciroot(0x%x)",
216                                     acpi->UID);
217                         case 0x0a08:
218                                 return snprintf(buf, size, "pcieroot(0x%x)",
219                                     acpi->UID);
220                         case 0x0604:
221                                 return snprintf(buf, size, "floppy(0x%x)",
222                                     acpi->UID);
223                         case 0x0301:
224                                 return snprintf(buf, size, "keyboard(0x%x)",
225                                     acpi->UID);
226                         case 0x0501:
227                                 return snprintf(buf, size, "serial(0x%x)",
228                                     acpi->UID);
229                         case 0x0401:
230                                 return snprintf(buf, size, "parallelport(0x%x)",
231                                     acpi->UID);
232                         default:
233                                 return snprintf(buf, size, "acpi(pnp%04x,0x%x)",
234                                     EISA_ID_TO_NUM(acpi->HID), acpi->UID);
235                         }
236                 }
237
238                 return snprintf(buf, size, "acpi(0x%08x,0x%x)", acpi->HID,
239                     acpi->UID);
240         }
241         case MEDIA_DEVICE_PATH:
242                 switch (devpath->SubType) {
243                 case MEDIA_CDROM_DP: {
244                         CDROM_DEVICE_PATH *cdrom;
245
246                         cdrom = (CDROM_DEVICE_PATH *)(void *)devpath;
247                         return snprintf(buf, size, "cdrom(%x)",
248                             cdrom->BootEntry);
249                 }
250                 case MEDIA_HARDDRIVE_DP: {
251                         HARDDRIVE_DEVICE_PATH *hd;
252
253                         hd = (HARDDRIVE_DEVICE_PATH *)(void *)devpath;
254                         return snprintf(buf, size, "hd(%x)",
255                             hd->PartitionNumber);
256                 }
257                 default:
258                         return snprintf(buf, size, "media(0x%02x)",
259                             devpath->SubType);
260                 }
261         case BBS_DEVICE_PATH:
262                 return snprintf(buf, size, "bbs(0x%02x)", devpath->SubType);
263         case END_DEVICE_PATH_TYPE:
264                 return (0);
265         }
266
267         return snprintf(buf, size, "type(0x%02x, 0x%02x)", devpath->Type,
268             devpath->SubType);
269 }
270
271 /*
272  * devpath_strlcat appends a text description of devpath to buf but not more
273  * than size - 1 characters followed by NUL-terminator.
274  */
275 int
276 devpath_strlcat(char *buf, size_t size, EFI_DEVICE_PATH *devpath)
277 {
278         size_t len, used;
279         const char *sep;
280
281         sep = "";
282         used = 0;
283         while (!IsDevicePathEnd(devpath)) {
284                 len = snprintf(buf, size - used, "%s", sep);
285                 used += len;
286                 if (used > size)
287                         return (used);
288                 buf += len;
289
290                 len = devpath_node_str(buf, size - used, devpath);
291                 used += len;
292                 if (used > size)
293                         return (used);
294                 buf += len;
295                 devpath = NextDevicePathNode(devpath);
296                 sep = ":";
297         }
298
299         return (used);
300 }
301
302 /*
303  * devpath_str is convenience method which returns the text description of
304  * devpath using a static buffer, so it isn't thread safe!
305  */
306 char *
307 devpath_str(EFI_DEVICE_PATH *devpath)
308 {
309         static char buf[256];
310
311         devpath_strlcat(buf, sizeof(buf), devpath);
312
313         return buf;
314 }
315
316 /*
317  * load_loader attempts to load the loader image data.
318  *
319  * It tries each module and its respective devices, identified by mod->probe,
320  * in order until a successful load occurs at which point it returns EFI_SUCCESS
321  * and EFI_NOT_FOUND otherwise.
322  *
323  * Only devices which have preferred matching the preferred parameter are tried.
324  */
325 static EFI_STATUS
326 load_loader(const boot_module_t **modp, dev_info_t **devinfop, void **bufp,
327     size_t *bufsize, BOOLEAN preferred)
328 {
329         UINTN i;
330         dev_info_t *dev;
331         const boot_module_t *mod;
332
333         for (i = 0; i < NUM_BOOT_MODULES; i++) {
334                 if (boot_modules[i] == NULL)
335                         continue;
336                 mod = boot_modules[i];
337                 for (dev = mod->devices(); dev != NULL; dev = dev->next) {
338                         if (dev->preferred != preferred)
339                                 continue;
340
341                         if (mod->load(PATH_LOADER_EFI, dev, bufp, bufsize) ==
342                             EFI_SUCCESS) {
343                                 *devinfop = dev;
344                                 *modp = mod;
345                                 return (EFI_SUCCESS);
346                         }
347                 }
348         }
349
350         return (EFI_NOT_FOUND);
351 }
352
353 /*
354  * try_boot only returns if it fails to load the loader. If it succeeds
355  * it simply boots, otherwise it returns the status of last EFI call.
356  */
357 static EFI_STATUS
358 try_boot()
359 {
360         size_t bufsize, loadersize, cmdsize;
361         void *buf, *loaderbuf;
362         char *cmd;
363         dev_info_t *dev;
364         const boot_module_t *mod;
365         EFI_HANDLE loaderhandle;
366         EFI_LOADED_IMAGE *loaded_image;
367         EFI_STATUS status;
368
369         status = load_loader(&mod, &dev, &loaderbuf, &loadersize, TRUE);
370         if (status != EFI_SUCCESS) {
371                 status = load_loader(&mod, &dev, &loaderbuf, &loadersize,
372                     FALSE);
373                 if (status != EFI_SUCCESS) {
374                         printf("Failed to load '%s'\n", PATH_LOADER_EFI);
375                         return (status);
376                 }
377         }
378
379         /*
380          * Read in and parse the command line from /boot.config or /boot/config,
381          * if present. We'll pass it the next stage via a simple ASCII
382          * string. loader.efi has a hack for ASCII strings, so we'll use that to
383          * keep the size down here. We only try to read the alternate file if
384          * we get EFI_NOT_FOUND because all other errors mean that the boot_module
385          * had troubles with the filesystem. We could return early, but we'll let
386          * loading the actual kernel sort all that out. Since these files are
387          * optional, we don't report errors in trying to read them.
388          */
389         cmd = NULL;
390         cmdsize = 0;
391         status = mod->load(PATH_DOTCONFIG, dev, &buf, &bufsize);
392         if (status == EFI_NOT_FOUND)
393                 status = mod->load(PATH_CONFIG, dev, &buf, &bufsize);
394         if (status == EFI_SUCCESS) {
395                 cmdsize = bufsize + 1;
396                 cmd = malloc(cmdsize);
397                 if (cmd == NULL)
398                         goto errout;
399                 memcpy(cmd, buf, bufsize);
400                 cmd[bufsize] = '\0';
401                 free(buf);
402                 buf = NULL;
403         }
404
405         if ((status = bs->LoadImage(TRUE, image, devpath_last(dev->devpath),
406             loaderbuf, loadersize, &loaderhandle)) != EFI_SUCCESS) {
407                 printf("Failed to load image provided by %s, size: %zu, (%lu)\n",
408                      mod->name, bufsize, EFI_ERROR_CODE(status));
409                 goto errout;
410         }
411
412         if ((status = bs->HandleProtocol(loaderhandle, &LoadedImageGUID,
413             (VOID**)&loaded_image)) != EFI_SUCCESS) {
414                 printf("Failed to query LoadedImage provided by %s (%lu)\n",
415                     mod->name, EFI_ERROR_CODE(status));
416                 goto errout;
417         }
418
419         if (cmd != NULL)
420                 printf("    command args: %s\n", cmd);
421
422         loaded_image->DeviceHandle = dev->devhandle;
423         loaded_image->LoadOptionsSize = cmdsize;
424         loaded_image->LoadOptions = cmd;
425
426         DPRINTF("Starting '%s' in 5 seconds...", PATH_LOADER_EFI);
427         DSTALL(1000000);
428         DPRINTF(".");
429         DSTALL(1000000);
430         DPRINTF(".");
431         DSTALL(1000000);
432         DPRINTF(".");
433         DSTALL(1000000);
434         DPRINTF(".");
435         DSTALL(1000000);
436         DPRINTF(".\n");
437
438         if ((status = bs->StartImage(loaderhandle, NULL, NULL)) !=
439             EFI_SUCCESS) {
440                 printf("Failed to start image provided by %s (%lu)\n",
441                     mod->name, EFI_ERROR_CODE(status));
442                 loaded_image->LoadOptionsSize = 0;
443                 loaded_image->LoadOptions = NULL;
444         }
445
446 errout:
447         if (cmd != NULL)
448                 free(cmd);
449         if (buf != NULL)
450                 free(buf);
451         if (loaderbuf != NULL)
452                 free(loaderbuf);
453
454         return (status);
455 }
456
457 /*
458  * probe_handle determines if the passed handle represents a logical partition
459  * if it does it uses each module in order to probe it and if successful it
460  * returns EFI_SUCCESS.
461  */
462 static EFI_STATUS
463 probe_handle(EFI_HANDLE h, EFI_DEVICE_PATH *imgpath, BOOLEAN *preferred)
464 {
465         dev_info_t *devinfo;
466         EFI_BLOCK_IO *blkio;
467         EFI_DEVICE_PATH *devpath;
468         EFI_STATUS status;
469         UINTN i;
470
471         /* Figure out if we're dealing with an actual partition. */
472         status = bs->HandleProtocol(h, &DevicePathGUID, (void **)&devpath);
473         if (status == EFI_UNSUPPORTED)
474                 return (status);
475
476         if (status != EFI_SUCCESS) {
477                 DPRINTF("\nFailed to query DevicePath (%lu)\n",
478                     EFI_ERROR_CODE(status));
479                 return (status);
480         }
481
482         DPRINTF("probing: %s\n", devpath_str(devpath));
483
484         status = bs->HandleProtocol(h, &BlockIoProtocolGUID, (void **)&blkio);
485         if (status == EFI_UNSUPPORTED)
486                 return (status);
487
488         if (status != EFI_SUCCESS) {
489                 DPRINTF("\nFailed to query BlockIoProtocol (%lu)\n",
490                     EFI_ERROR_CODE(status));
491                 return (status);
492         }
493
494         if (!blkio->Media->LogicalPartition)
495                 return (EFI_UNSUPPORTED);
496
497         *preferred = device_paths_match(imgpath, devpath);
498
499         /* Run through each module, see if it can load this partition */
500         for (i = 0; i < NUM_BOOT_MODULES; i++) {
501                 if (boot_modules[i] == NULL)
502                         continue;
503
504                 if ((status = bs->AllocatePool(EfiLoaderData,
505                     sizeof(*devinfo), (void **)&devinfo)) !=
506                     EFI_SUCCESS) {
507                         DPRINTF("\nFailed to allocate devinfo (%lu)\n",
508                             EFI_ERROR_CODE(status));
509                         continue;
510                 }
511                 devinfo->dev = blkio;
512                 devinfo->devpath = devpath;
513                 devinfo->devhandle = h;
514                 devinfo->devdata = NULL;
515                 devinfo->preferred = *preferred;
516                 devinfo->next = NULL;
517
518                 status = boot_modules[i]->probe(devinfo);
519                 if (status == EFI_SUCCESS)
520                         return (EFI_SUCCESS);
521                 (void)bs->FreePool(devinfo);
522         }
523
524         return (EFI_UNSUPPORTED);
525 }
526
527 /*
528  * probe_handle_status calls probe_handle and outputs the returned status
529  * of the call.
530  */
531 static void
532 probe_handle_status(EFI_HANDLE h, EFI_DEVICE_PATH *imgpath)
533 {
534         EFI_STATUS status;
535         BOOLEAN preferred;
536
537         status = probe_handle(h, imgpath, &preferred);
538         
539         DPRINTF("probe: ");
540         switch (status) {
541         case EFI_UNSUPPORTED:
542                 printf(".");
543                 DPRINTF(" not supported\n");
544                 break;
545         case EFI_SUCCESS:
546                 if (preferred) {
547                         printf("%c", '*');
548                         DPRINTF(" supported (preferred)\n");
549                 } else {
550                         printf("%c", '+');
551                         DPRINTF(" supported\n");
552                 }
553                 break;
554         default:
555                 printf("x");
556                 DPRINTF(" error (%lu)\n", EFI_ERROR_CODE(status));
557                 break;
558         }
559         DSTALL(500000);
560 }
561
562 EFI_STATUS
563 efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE *Xsystab)
564 {
565         EFI_HANDLE *handles;
566         EFI_LOADED_IMAGE *img;
567         EFI_DEVICE_PATH *imgpath;
568         EFI_STATUS status;
569         EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl = NULL;
570         SIMPLE_TEXT_OUTPUT_INTERFACE *conout = NULL;
571         UINTN i, max_dim, best_mode, cols, rows, hsize, nhandles;
572
573         /* Basic initialization*/
574         systab = Xsystab;
575         image = Ximage;
576         bs = Xsystab->BootServices;
577
578         /* Set up the console, so printf works. */
579         status = bs->LocateProtocol(&ConsoleControlGUID, NULL,
580             (VOID **)&ConsoleControl);
581         if (status == EFI_SUCCESS)
582                 (void)ConsoleControl->SetMode(ConsoleControl,
583                     EfiConsoleControlScreenText);
584         /*
585          * Reset the console and find the best text mode.
586          */
587         conout = systab->ConOut;
588         conout->Reset(conout, TRUE);
589         max_dim = best_mode = 0;
590         for (i = 0; ; i++) {
591                 status = conout->QueryMode(conout, i, &cols, &rows);
592                 if (EFI_ERROR(status))
593                         break;
594                 if (cols * rows > max_dim) {
595                         max_dim = cols * rows;
596                         best_mode = i;
597                 }
598         }
599         if (max_dim > 0)
600                 conout->SetMode(conout, best_mode);
601         conout->EnableCursor(conout, TRUE);
602         conout->ClearScreen(conout);
603
604         printf("\n>> FreeBSD EFI boot block\n");
605         printf("   Loader path: %s\n\n", PATH_LOADER_EFI);
606         printf("   Initializing modules:");
607         for (i = 0; i < NUM_BOOT_MODULES; i++) {
608                 if (boot_modules[i] == NULL)
609                         continue;
610
611                 printf(" %s", boot_modules[i]->name);
612                 if (boot_modules[i]->init != NULL)
613                         boot_modules[i]->init();
614         }
615         putchar('\n');
616
617         /* Get all the device handles */
618         hsize = (UINTN)NUM_HANDLES_INIT * sizeof(EFI_HANDLE);
619         if ((status = bs->AllocatePool(EfiLoaderData, hsize, (void **)&handles))
620             != EFI_SUCCESS)
621                 panic("Failed to allocate %d handles (%lu)", NUM_HANDLES_INIT,
622                     EFI_ERROR_CODE(status));
623
624         status = bs->LocateHandle(ByProtocol, &BlockIoProtocolGUID, NULL,
625             &hsize, handles);
626         switch (status) {
627         case EFI_SUCCESS:
628                 break;
629         case EFI_BUFFER_TOO_SMALL:
630                 (void)bs->FreePool(handles);
631                 if ((status = bs->AllocatePool(EfiLoaderData, hsize,
632                     (void **)&handles) != EFI_SUCCESS)) {
633                         panic("Failed to allocate %zu handles (%lu)", hsize /
634                             sizeof(*handles), EFI_ERROR_CODE(status));
635                 }
636                 status = bs->LocateHandle(ByProtocol, &BlockIoProtocolGUID,
637                     NULL, &hsize, handles);
638                 if (status != EFI_SUCCESS)
639                         panic("Failed to get device handles (%lu)\n",
640                             EFI_ERROR_CODE(status));
641                 break;
642         default:
643                 panic("Failed to get device handles (%lu)",
644                     EFI_ERROR_CODE(status));
645         }
646
647         /* Scan all partitions, probing with all modules. */
648         nhandles = hsize / sizeof(*handles);
649         printf("   Probing %zu block devices...", nhandles);
650         DPRINTF("\n");
651
652         /* Determine the devpath of our image so we can prefer it. */
653         status = bs->HandleProtocol(image, &LoadedImageGUID, (VOID**)&img);
654         imgpath = NULL;
655         if (status == EFI_SUCCESS) {
656                 status = bs->HandleProtocol(img->DeviceHandle, &DevicePathGUID,
657                     (void **)&imgpath);
658                 if (status != EFI_SUCCESS)
659                         DPRINTF("Failed to get image DevicePath (%lu)\n",
660                             EFI_ERROR_CODE(status));
661                 DPRINTF("boot1 imagepath: %s\n", devpath_str(imgpath));
662         }
663
664         for (i = 0; i < nhandles; i++)
665                 probe_handle_status(handles[i], imgpath);
666         printf(" done\n");
667
668         /* Status summary. */
669         for (i = 0; i < NUM_BOOT_MODULES; i++) {
670                 if (boot_modules[i] != NULL) {
671                         printf("    ");
672                         boot_modules[i]->status();
673                 }
674         }
675
676         try_boot();
677
678         /* If we get here, we're out of luck... */
679         panic("No bootable partitions found!");
680 }
681
682 /*
683  * add_device adds a device to the passed devinfo list.
684  */
685 void
686 add_device(dev_info_t **devinfop, dev_info_t *devinfo)
687 {
688         dev_info_t *dev;
689
690         if (*devinfop == NULL) {
691                 *devinfop = devinfo;
692                 return;
693         }
694
695         for (dev = *devinfop; dev->next != NULL; dev = dev->next)
696                 ;
697
698         dev->next = devinfo;
699 }
700
701 void
702 panic(const char *fmt, ...)
703 {
704         va_list ap;
705
706         printf("panic: ");
707         va_start(ap, fmt);
708         vprintf(fmt, ap);
709         va_end(ap);
710         printf("\n");
711
712         while (1) {}
713 }
714
715 void
716 putchar(int c)
717 {
718         CHAR16 buf[2];
719
720         if (c == '\n') {
721                 buf[0] = '\r';
722                 buf[1] = 0;
723                 systab->ConOut->OutputString(systab->ConOut, buf);
724         }
725         buf[0] = c;
726         buf[1] = 0;
727         systab->ConOut->OutputString(systab->ConOut, buf);
728 }