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