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