Lines 28-34
Link Here
|
28 |
#include <stand.h> |
28 |
#include <stand.h> |
29 |
|
29 |
|
30 |
#include <efi.h> |
30 |
#include <efi.h> |
31 |
#include <eficonsctl.h> |
31 |
#include <efilib.h> |
32 |
|
32 |
|
33 |
#include "boot_module.h" |
33 |
#include "boot_module.h" |
34 |
#include "paths.h" |
34 |
#include "paths.h" |
Lines 47-63
Link Here
|
47 |
/* The initial number of handles used to query EFI for partitions. */ |
47 |
/* The initial number of handles used to query EFI for partitions. */ |
48 |
#define NUM_HANDLES_INIT 24 |
48 |
#define NUM_HANDLES_INIT 24 |
49 |
|
49 |
|
|
|
50 |
void efi_cons_putchar(int); |
51 |
int efi_cons_getchar(void); |
52 |
int efi_cons_poll(void); |
53 |
int getchar(void); |
50 |
void putchar(int c); |
54 |
void putchar(int c); |
|
|
55 |
char *humanize_number_kmgt(UINT64); |
51 |
EFI_STATUS efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE* Xsystab); |
56 |
EFI_STATUS efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE* Xsystab); |
52 |
|
57 |
|
53 |
EFI_SYSTEM_TABLE *systab; |
58 |
EFI_SYSTEM_TABLE *systab; |
54 |
EFI_BOOT_SERVICES *bs; |
59 |
EFI_BOOT_SERVICES *bs; |
55 |
static EFI_HANDLE *image; |
60 |
static EFI_HANDLE *image; |
|
|
61 |
static SIMPLE_TEXT_OUTPUT_INTERFACE *conout; |
62 |
static SIMPLE_INPUT_INTERFACE *conin; |
56 |
|
63 |
|
57 |
static EFI_GUID BlockIoProtocolGUID = BLOCK_IO_PROTOCOL; |
64 |
static EFI_GUID BlockIoProtocolGUID = BLOCK_IO_PROTOCOL; |
58 |
static EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL; |
65 |
static EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL; |
59 |
static EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL; |
66 |
static EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL; |
60 |
static EFI_GUID ConsoleControlGUID = EFI_CONSOLE_CONTROL_PROTOCOL_GUID; |
67 |
|
|
|
68 |
#define DEFAULT_FGCOLOR EFI_LIGHTGRAY |
69 |
#define DEFAULT_BGCOLOR EFI_BLACK |
70 |
|
71 |
char *humanize_number_kmgt(UINT64 size) { |
72 |
static char buf2[6]; |
73 |
UINT64 size0; |
74 |
|
75 |
if (size < 1024) |
76 |
sprintf(buf2, "%luB", size); |
77 |
else if (size0 = (size*10+512)/1024, size0 < 100) |
78 |
sprintf(buf2, "%lu.%luK", size0 / 10, size0 % 10); |
79 |
else if (size0 = (size+512)/1024, size0 < 1024) |
80 |
sprintf(buf2, "%luK", size0); |
81 |
else if (size0 = (size*10/1024+512)/1024, size0 < 100) |
82 |
sprintf(buf2, "%lu.%luM", size0 / 10, size0 % 10); |
83 |
else if (size0 = (size/1024+512)/1024, size0 < 1024) |
84 |
sprintf(buf2, "%luM", size0); |
85 |
else if (size0 = (size*10/1024/1024+512)/1024, size0 < 100) |
86 |
sprintf(buf2, "%lu.%luG", size0 / 10, size0 % 10); |
87 |
else if (size0 = (size/1024/1024+512)/1024, size0 < 1024) |
88 |
sprintf(buf2, "%luG", size0); |
89 |
else if (size0 = (size*10/1024/1024/1024+512)/1024, size0 < 100) |
90 |
sprintf(buf2, "%lu.%luT", size0 / 10, size0 % 10); |
91 |
else |
92 |
sprintf(buf2, "%luT", (size/1024/1024/1024+512)/1024); |
93 |
return(buf2); |
94 |
} |
61 |
|
95 |
|
62 |
/* |
96 |
/* |
63 |
* Provide Malloc / Free backed by EFIs AllocatePool / FreePool which ensures |
97 |
* Provide Malloc / Free backed by EFIs AllocatePool / FreePool which ensures |
Lines 151-157
Link Here
|
151 |
static int |
185 |
static int |
152 |
devpath_node_str(char *buf, size_t size, EFI_DEVICE_PATH *devpath) |
186 |
devpath_node_str(char *buf, size_t size, EFI_DEVICE_PATH *devpath) |
153 |
{ |
187 |
{ |
154 |
|
|
|
155 |
switch (devpath->Type) { |
188 |
switch (devpath->Type) { |
156 |
case MESSAGING_DEVICE_PATH: |
189 |
case MESSAGING_DEVICE_PATH: |
157 |
switch (devpath->SubType) { |
190 |
switch (devpath->SubType) { |
Lines 251-258
Link Here
|
251 |
HARDDRIVE_DEVICE_PATH *hd; |
284 |
HARDDRIVE_DEVICE_PATH *hd; |
252 |
|
285 |
|
253 |
hd = (HARDDRIVE_DEVICE_PATH *)(void *)devpath; |
286 |
hd = (HARDDRIVE_DEVICE_PATH *)(void *)devpath; |
254 |
return snprintf(buf, size, "hd(%x)", |
287 |
return snprintf(buf, size, "hd(p%d) (%s)", |
255 |
hd->PartitionNumber); |
288 |
hd->PartitionNumber, |
|
|
289 |
humanize_number_kmgt(hd->PartitionSize * 512)); |
256 |
} |
290 |
} |
257 |
default: |
291 |
default: |
258 |
return snprintf(buf, size, "media(0x%02x)", |
292 |
return snprintf(buf, size, "media(0x%02x)", |
Lines 350-355
Link Here
|
350 |
return (EFI_NOT_FOUND); |
384 |
return (EFI_NOT_FOUND); |
351 |
} |
385 |
} |
352 |
|
386 |
|
|
|
387 |
/* quick dirty work. */ |
388 |
#define NUM_DEV_LIST 35 |
389 |
|
390 |
static struct dev_list_t { |
391 |
const boot_module_t *modp; |
392 |
dev_info_t *devinfop; |
393 |
} dev_list[NUM_DEV_LIST]; |
394 |
|
395 |
static int |
396 |
list_devices(void) |
397 |
{ |
398 |
UINTN i, j; |
399 |
dev_info_t *dev; |
400 |
const boot_module_t *mod; |
401 |
|
402 |
j = 0; |
403 |
for (i = 0; i < NUM_BOOT_MODULES; i++) { |
404 |
if (boot_modules[i] == NULL) |
405 |
continue; |
406 |
mod = boot_modules[i]; |
407 |
for (dev = mod->devices(); dev != NULL; dev = dev->next) { |
408 |
dev_list[j].devinfop = dev; |
409 |
dev_list[j].modp = mod; |
410 |
j++; |
411 |
if (j >= NUM_DEV_LIST) |
412 |
break; |
413 |
} |
414 |
} |
415 |
|
416 |
return (j); |
417 |
} |
418 |
|
419 |
#define SELECT_TIMEOUT 10 |
420 |
|
421 |
static int |
422 |
select_dev(int ndevs) |
423 |
{ |
424 |
int i; |
425 |
int c; |
426 |
static int timeout = TRUE; |
427 |
|
428 |
printf(" 0: AutoSelected Partition (Default): 0\n"); |
429 |
for (i = 0; i < ndevs; i++) { |
430 |
if (dev_list[i].devinfop->preferred == TRUE) |
431 |
c = '*'; |
432 |
else |
433 |
c = ' '; |
434 |
printf(" %c%c: %s: %s: %c\n", c, i<9 ? '1'+i : 'a'+i-9, |
435 |
dev_list[i].modp->name, |
436 |
devpath_str(dev_list[i].devinfop->devpath), |
437 |
i<9 ? '1'+i : 'a'+i-9); |
438 |
} |
439 |
/* One digit selection only. Is this big enough ?? */ |
440 |
while (1) { |
441 |
if (timeout) |
442 |
printf("Select from 0 to %c: Timeout in %2d seconds" |
443 |
"\b\b\b\b\b\b\b\b\b\b", |
444 |
ndevs<10 ? '0'+ndevs : 'a'+ndevs-10, |
445 |
SELECT_TIMEOUT); |
446 |
else |
447 |
printf("Select from 0 to %c: Never timeout", |
448 |
ndevs<10 ? '0'+ndevs : 'a'+ndevs-10); |
449 |
for (i = SELECT_TIMEOUT * 20; i > 0; i--) { |
450 |
if (timeout) { |
451 |
if (!(i % 20)) |
452 |
printf("%2d\b\b", i / 20); |
453 |
bs->Stall(50000); |
454 |
if (!efi_cons_poll()) /* No Key */ |
455 |
continue; |
456 |
} |
457 |
while (1) { |
458 |
if (timeout) { |
459 |
printf("\b\b\b\b\b\b\b\b\b\b\b" |
460 |
"Never timeout "); |
461 |
timeout = FALSE; |
462 |
} |
463 |
c = getchar(); |
464 |
c = (c == 0x0d) ? 0 : |
465 |
(c >= '0' && c <= '9') ? c - '0' : |
466 |
(c >= 'A' && c <= 'Z') ? c - 'A' + 10 : |
467 |
(c >= 'a' && c <= 'z') ? c - 'a' + 10 : |
468 |
ndevs + 1; |
469 |
if ((c >= 0) && (c <= ndevs)) { |
470 |
putchar('\n'); |
471 |
return (c); |
472 |
} |
473 |
} |
474 |
} |
475 |
printf(" 0\nTimeout. Partition is AutoSelected.\n"); |
476 |
return (0); |
477 |
} |
478 |
} |
479 |
|
353 |
/* |
480 |
/* |
354 |
* try_boot only returns if it fails to load the loader. If it succeeds |
481 |
* 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. |
482 |
* it simply boots, otherwise it returns the status of last EFI call. |
Lines 358-379
Link Here
|
358 |
try_boot() |
485 |
try_boot() |
359 |
{ |
486 |
{ |
360 |
size_t bufsize, loadersize, cmdsize; |
487 |
size_t bufsize, loadersize, cmdsize; |
361 |
void *buf, *loaderbuf; |
488 |
void *buf = NULL, *loaderbuf = NULL; |
362 |
char *cmd; |
489 |
char *cmd; |
363 |
dev_info_t *dev; |
490 |
dev_info_t *dev; |
364 |
const boot_module_t *mod; |
491 |
const boot_module_t *mod; |
365 |
EFI_HANDLE loaderhandle; |
492 |
EFI_HANDLE loaderhandle; |
366 |
EFI_LOADED_IMAGE *loaded_image; |
493 |
EFI_LOADED_IMAGE *loaded_image; |
367 |
EFI_STATUS status; |
494 |
EFI_STATUS status; |
|
|
495 |
int i, ndevs; |
368 |
|
496 |
|
369 |
status = load_loader(&mod, &dev, &loaderbuf, &loadersize, TRUE); |
497 |
ndevs = list_devices(); |
370 |
if (status != EFI_SUCCESS) { |
498 |
if (ndevs == 0) { |
371 |
status = load_loader(&mod, &dev, &loaderbuf, &loadersize, |
499 |
printf("Failed to load '%s'\n", PATH_LOADER_EFI); |
372 |
FALSE); |
500 |
return (EFI_NOT_FOUND); |
|
|
501 |
} else if (ndevs == 1) { |
502 |
mod = dev_list[0].modp; |
503 |
dev = dev_list[0].devinfop; |
504 |
status = mod->load(PATH_LOADER_EFI, dev, |
505 |
&loaderbuf, &loadersize); |
373 |
if (status != EFI_SUCCESS) { |
506 |
if (status != EFI_SUCCESS) { |
374 |
printf("Failed to load '%s'\n", PATH_LOADER_EFI); |
507 |
printf("Failed to load '%s'\n", PATH_LOADER_EFI); |
375 |
return (status); |
508 |
return (status); |
376 |
} |
509 |
} |
|
|
510 |
} else { |
511 |
while (1) { |
512 |
i = select_dev(ndevs); |
513 |
printf(" %c is selected.\n", i<10 ? '0'+i : 'a'+i-10); |
514 |
if (i == 0) { /* AutoSelect */ |
515 |
status = load_loader(&mod, &dev, &loaderbuf, &loadersize, TRUE); |
516 |
if (status != EFI_SUCCESS) { |
517 |
status = load_loader(&mod, &dev, &loaderbuf, &loadersize, |
518 |
FALSE); |
519 |
if (status != EFI_SUCCESS) { |
520 |
printf("Failed to load '%s'\n", PATH_LOADER_EFI); |
521 |
return (status); |
522 |
} |
523 |
} |
524 |
break; |
525 |
} else { |
526 |
mod = dev_list[i-1].modp; |
527 |
dev = dev_list[i-1].devinfop; |
528 |
status = mod->load(PATH_LOADER_EFI, dev, |
529 |
&loaderbuf, &loadersize); |
530 |
if (status == EFI_SUCCESS) |
531 |
break; |
532 |
printf("Failed to load '%s'\n", PATH_LOADER_EFI); |
533 |
} |
534 |
printf("Please select again.\n"); |
535 |
} |
377 |
} |
536 |
} |
378 |
|
537 |
|
379 |
/* |
538 |
/* |
Lines 423-428
Link Here
|
423 |
loaded_image->LoadOptionsSize = cmdsize; |
582 |
loaded_image->LoadOptionsSize = cmdsize; |
424 |
loaded_image->LoadOptions = cmd; |
583 |
loaded_image->LoadOptions = cmd; |
425 |
|
584 |
|
|
|
585 |
printf("Boot from: %s in 1 second\n", devpath_str(dev->devpath)); |
586 |
bs->Stall(1000000); |
587 |
|
426 |
DPRINTF("Starting '%s' in 5 seconds...", PATH_LOADER_EFI); |
588 |
DPRINTF("Starting '%s' in 5 seconds...", PATH_LOADER_EFI); |
427 |
DSTALL(1000000); |
589 |
DSTALL(1000000); |
428 |
DPRINTF("."); |
590 |
DPRINTF("."); |
Lines 556-591
Link Here
|
556 |
DPRINTF(" error (%lu)\n", EFI_ERROR_CODE(status)); |
718 |
DPRINTF(" error (%lu)\n", EFI_ERROR_CODE(status)); |
557 |
break; |
719 |
break; |
558 |
} |
720 |
} |
559 |
DSTALL(500000); |
721 |
DSTALL(1000000); |
560 |
} |
722 |
} |
561 |
|
723 |
|
562 |
EFI_STATUS |
724 |
static EFI_STATUS |
563 |
efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE *Xsystab) |
725 |
init_console() |
564 |
{ |
726 |
{ |
565 |
EFI_HANDLE *handles; |
|
|
566 |
EFI_LOADED_IMAGE *img; |
567 |
EFI_DEVICE_PATH *imgpath; |
568 |
EFI_STATUS status; |
727 |
EFI_STATUS status; |
569 |
EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl = NULL; |
728 |
UINTN i, max_dim, best_mode, cols, rows; |
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 |
|
729 |
|
578 |
/* Set up the console, so printf works. */ |
730 |
/* 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 |
/* |
731 |
/* |
585 |
* Reset the console and find the best text mode. |
732 |
* Reset the console and find the best text mode. |
586 |
*/ |
733 |
*/ |
|
|
734 |
conin = systab->ConIn; |
587 |
conout = systab->ConOut; |
735 |
conout = systab->ConOut; |
|
|
736 |
conin->Reset(conin, TRUE); |
588 |
conout->Reset(conout, TRUE); |
737 |
conout->Reset(conout, TRUE); |
|
|
738 |
|
589 |
max_dim = best_mode = 0; |
739 |
max_dim = best_mode = 0; |
590 |
for (i = 0; ; i++) { |
740 |
for (i = 0; ; i++) { |
591 |
status = conout->QueryMode(conout, i, &cols, &rows); |
741 |
status = conout->QueryMode(conout, i, &cols, &rows); |
Lines 598-606
Link Here
|
598 |
} |
748 |
} |
599 |
if (max_dim > 0) |
749 |
if (max_dim > 0) |
600 |
conout->SetMode(conout, best_mode); |
750 |
conout->SetMode(conout, best_mode); |
|
|
751 |
|
752 |
conout->SetAttribute(conout, EFI_TEXT_ATTR(DEFAULT_FGCOLOR, |
753 |
DEFAULT_BGCOLOR)); |
601 |
conout->EnableCursor(conout, TRUE); |
754 |
conout->EnableCursor(conout, TRUE); |
602 |
conout->ClearScreen(conout); |
755 |
conout->ClearScreen(conout); |
603 |
|
756 |
|
|
|
757 |
return (status); |
758 |
} |
759 |
|
760 |
EFI_STATUS |
761 |
efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE *Xsystab) |
762 |
{ |
763 |
EFI_HANDLE *handles; |
764 |
EFI_LOADED_IMAGE *img; |
765 |
EFI_DEVICE_PATH *imgpath; |
766 |
EFI_STATUS status; |
767 |
UINTN i, hsize, nhandles; |
768 |
|
769 |
/* Basic initialization*/ |
770 |
systab = Xsystab; |
771 |
image = Ximage; |
772 |
bs = Xsystab->BootServices; |
773 |
|
774 |
init_console(); |
775 |
|
604 |
printf("\n>> FreeBSD EFI boot block\n"); |
776 |
printf("\n>> FreeBSD EFI boot block\n"); |
605 |
printf(" Loader path: %s\n\n", PATH_LOADER_EFI); |
777 |
printf(" Loader path: %s\n\n", PATH_LOADER_EFI); |
606 |
printf(" Initializing modules:"); |
778 |
printf(" Initializing modules:"); |
Lines 715-728
Link Here
|
715 |
void |
887 |
void |
716 |
putchar(int c) |
888 |
putchar(int c) |
717 |
{ |
889 |
{ |
|
|
890 |
efi_cons_putchar(c); |
891 |
} |
892 |
|
893 |
void |
894 |
efi_cons_putchar(int c) |
895 |
{ |
718 |
CHAR16 buf[2]; |
896 |
CHAR16 buf[2]; |
719 |
|
897 |
|
720 |
if (c == '\n') { |
898 |
if (c == '\n') { |
721 |
buf[0] = '\r'; |
899 |
buf[0] = '\r'; |
722 |
buf[1] = 0; |
900 |
buf[1] = 0; |
723 |
systab->ConOut->OutputString(systab->ConOut, buf); |
901 |
conout->OutputString(conout, buf); |
724 |
} |
902 |
} |
725 |
buf[0] = c; |
903 |
buf[0] = c; |
726 |
buf[1] = 0; |
904 |
buf[1] = 0; |
727 |
systab->ConOut->OutputString(systab->ConOut, buf); |
905 |
conout->OutputString(conout, buf); |
|
|
906 |
} |
907 |
|
908 |
int |
909 |
getchar(void) |
910 |
{ |
911 |
return efi_cons_getchar(); |
912 |
} |
913 |
|
914 |
|
915 |
int |
916 |
efi_cons_getchar() |
917 |
{ |
918 |
EFI_INPUT_KEY key; |
919 |
EFI_STATUS status; |
920 |
UINTN junk; |
921 |
|
922 |
/* Try to read a key stroke. We wait for one if none is pending. */ |
923 |
status = conin->ReadKeyStroke(conin, &key); |
924 |
if (status == EFI_NOT_READY) { |
925 |
bs->WaitForEvent(1, &conin->WaitForKey, &junk); |
926 |
status = conin->ReadKeyStroke(conin, &key); |
927 |
} |
928 |
switch (key.ScanCode) { |
929 |
case 0x17: /* ESC */ |
930 |
return (0x1b); /* esc */ |
931 |
} |
932 |
|
933 |
/* this can return */ |
934 |
return (key.UnicodeChar); |
728 |
} |
935 |
} |
|
|
936 |
|
937 |
int |
938 |
efi_cons_poll() |
939 |
{ |
940 |
/* This can clear the signaled state. */ |
941 |
return (bs->CheckEvent(conin->WaitForKey) == EFI_SUCCESS); |
942 |
} |
943 |
|