Lines 29-34
Link Here
|
29 |
|
29 |
|
30 |
#include <efi.h> |
30 |
#include <efi.h> |
31 |
#include <eficonsctl.h> |
31 |
#include <eficonsctl.h> |
|
|
32 |
#include <efilib.h> |
32 |
|
33 |
|
33 |
#include "boot_module.h" |
34 |
#include "boot_module.h" |
34 |
#include "paths.h" |
35 |
#include "paths.h" |
Lines 47-58
Link Here
|
47 |
/* The initial number of handles used to query EFI for partitions. */ |
48 |
/* The initial number of handles used to query EFI for partitions. */ |
48 |
#define NUM_HANDLES_INIT 24 |
49 |
#define NUM_HANDLES_INIT 24 |
49 |
|
50 |
|
|
|
51 |
void efi_cons_putchar(int); |
52 |
int efi_cons_getchar(void); |
53 |
int efi_cons_poll(void); |
54 |
int getchar(void); |
50 |
void putchar(int c); |
55 |
void putchar(int c); |
|
|
56 |
char *humanize_number_kmgt(UINT64); |
51 |
EFI_STATUS efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE* Xsystab); |
57 |
EFI_STATUS efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE* Xsystab); |
52 |
|
58 |
|
53 |
EFI_SYSTEM_TABLE *systab; |
59 |
EFI_SYSTEM_TABLE *systab; |
54 |
EFI_BOOT_SERVICES *bs; |
60 |
EFI_BOOT_SERVICES *bs; |
55 |
static EFI_HANDLE *image; |
61 |
static EFI_HANDLE *image; |
|
|
62 |
static SIMPLE_TEXT_OUTPUT_INTERFACE *conout; |
63 |
static SIMPLE_INPUT_INTERFACE *conin; |
56 |
|
64 |
|
57 |
static EFI_GUID BlockIoProtocolGUID = BLOCK_IO_PROTOCOL; |
65 |
static EFI_GUID BlockIoProtocolGUID = BLOCK_IO_PROTOCOL; |
58 |
static EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL; |
66 |
static EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL; |
Lines 59-64
Link Here
|
59 |
static EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL; |
67 |
static EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL; |
60 |
static EFI_GUID ConsoleControlGUID = EFI_CONSOLE_CONTROL_PROTOCOL_GUID; |
68 |
static EFI_GUID ConsoleControlGUID = EFI_CONSOLE_CONTROL_PROTOCOL_GUID; |
61 |
|
69 |
|
|
|
70 |
|
71 |
#define DEFAULT_FGCOLOR EFI_LIGHTGRAY |
72 |
#define DEFAULT_BGCOLOR EFI_BLACK |
73 |
|
74 |
char *humanize_number_kmgt(UINT64 size) { |
75 |
static char buf2[6]; |
76 |
UINT64 size0; |
77 |
|
78 |
if (size < 1024) |
79 |
sprintf(buf2, "%luB", size); |
80 |
else if (size0 = (size*10+512)/1024, size0 < 100) |
81 |
sprintf(buf2, "%lu.%luK", size0 / 10, size0 % 10); |
82 |
else if (size0 = (size+512)/1024, size0 < 1024) |
83 |
sprintf(buf2, "%luK", size0); |
84 |
else if (size0 = (size*10/1024+512)/1024, size0 < 100) |
85 |
sprintf(buf2, "%lu.%luM", size0 / 10, size0 % 10); |
86 |
else if (size0 = (size/1024+512)/1024, size0 < 1024) |
87 |
sprintf(buf2, "%luM", size0); |
88 |
else if (size0 = (size*10/1024/1024+512)/1024, size0 < 100) |
89 |
sprintf(buf2, "%lu.%luG", size0 / 10, size0 % 10); |
90 |
else if (size0 = (size/1024/1024+512)/1024, size0 < 1024) |
91 |
sprintf(buf2, "%luG", size0); |
92 |
else if (size0 = (size*10/1024/1024/1024+512)/1024, size0 < 100) |
93 |
sprintf(buf2, "%lu.%luT", size0 / 10, size0 % 10); |
94 |
else |
95 |
sprintf(buf2, "%luT", (size/1024/1024/1024+512)/1024); |
96 |
return(buf2); |
97 |
} |
98 |
|
62 |
/* |
99 |
/* |
63 |
* Provide Malloc / Free backed by EFIs AllocatePool / FreePool which ensures |
100 |
* Provide Malloc / Free backed by EFIs AllocatePool / FreePool which ensures |
64 |
* memory is correctly aligned avoiding EFI_INVALID_PARAMETER returns from |
101 |
* memory is correctly aligned avoiding EFI_INVALID_PARAMETER returns from |
Lines 151-157
Link Here
|
151 |
static int |
188 |
static int |
152 |
devpath_node_str(char *buf, size_t size, EFI_DEVICE_PATH *devpath) |
189 |
devpath_node_str(char *buf, size_t size, EFI_DEVICE_PATH *devpath) |
153 |
{ |
190 |
{ |
154 |
|
|
|
155 |
switch (devpath->Type) { |
191 |
switch (devpath->Type) { |
156 |
case MESSAGING_DEVICE_PATH: |
192 |
case MESSAGING_DEVICE_PATH: |
157 |
switch (devpath->SubType) { |
193 |
switch (devpath->SubType) { |
Lines 251-258
Link Here
|
251 |
HARDDRIVE_DEVICE_PATH *hd; |
287 |
HARDDRIVE_DEVICE_PATH *hd; |
252 |
|
288 |
|
253 |
hd = (HARDDRIVE_DEVICE_PATH *)(void *)devpath; |
289 |
hd = (HARDDRIVE_DEVICE_PATH *)(void *)devpath; |
254 |
return snprintf(buf, size, "hd(%x)", |
290 |
return snprintf(buf, size, "hd(p%d) (%s)", |
255 |
hd->PartitionNumber); |
291 |
hd->PartitionNumber, |
|
|
292 |
humanize_number_kmgt(hd->PartitionSize * 512)); |
256 |
} |
293 |
} |
257 |
default: |
294 |
default: |
258 |
return snprintf(buf, size, "media(0x%02x)", |
295 |
return snprintf(buf, size, "media(0x%02x)", |
Lines 350-355
Link Here
|
350 |
return (EFI_NOT_FOUND); |
387 |
return (EFI_NOT_FOUND); |
351 |
} |
388 |
} |
352 |
|
389 |
|
|
|
390 |
/* quick dirty work. */ |
391 |
#define NUM_DEV_LIST 35 |
392 |
|
393 |
typedef struct { |
394 |
const boot_module_t *modp; |
395 |
dev_info_t *devinfop; |
396 |
} moddev_t; |
397 |
|
398 |
static moddev_t dev_list[NUM_DEV_LIST]; |
399 |
|
400 |
static int |
401 |
list_devices(void) |
402 |
{ |
403 |
UINTN i, j; |
404 |
dev_info_t *dev; |
405 |
const boot_module_t *mod; |
406 |
|
407 |
j = 0; |
408 |
for (i = 0; i < NUM_BOOT_MODULES; i++) { |
409 |
if (boot_modules[i] == NULL) |
410 |
continue; |
411 |
mod = boot_modules[i]; |
412 |
for (dev = mod->devices(); dev != NULL; dev = dev->next) { |
413 |
dev_list[j].devinfop = dev; |
414 |
dev_list[j].modp = mod; |
415 |
j++; |
416 |
if (j >= NUM_DEV_LIST) |
417 |
break; |
418 |
} |
419 |
} |
420 |
|
421 |
return (j); |
422 |
} |
423 |
|
424 |
#define SELECT_TIMEOUT 10 |
425 |
|
426 |
static char |
427 |
idx2char(int i) |
428 |
{ |
429 |
return (i<10 ? '0'+i : 'a'+i-10); |
430 |
} |
431 |
|
432 |
static int |
433 |
char2idx(char c) |
434 |
{ |
435 |
return ((c >= '0' && c <= '9') ? c - '0' : |
436 |
(c >= 'A' && c <= 'Z') ? c - 'A' + 10 : |
437 |
(c >= 'a' && c <= 'z') ? c - 'a' + 10 : |
438 |
-1 ); |
439 |
} |
440 |
|
441 |
static void |
442 |
move_to_tol() |
443 |
{ |
444 |
int x,y; |
445 |
|
446 |
x = conout->Mode->CursorColumn; |
447 |
y = conout->Mode->CursorRow; |
448 |
conout->SetCursorPosition(conout, 0, y); |
449 |
} |
450 |
|
451 |
static EFI_STATUS |
452 |
select_bootdev(int ndevs, const boot_module_t **modp, dev_info_t **devinfop, |
453 |
void **bufp, size_t *bufsize) |
454 |
{ |
455 |
int i; |
456 |
int c, n; |
457 |
int time_left; |
458 |
EFI_STATUS status; |
459 |
EFI_EVENT timer; |
460 |
EFI_EVENT events[2]; |
461 |
UINTN idx; |
462 |
dev_info_t *dev; |
463 |
const boot_module_t *mod; |
464 |
|
465 |
if ((ndevs <= 0) || (ndevs >= NUM_DEV_LIST)) { |
466 |
return (EFI_NOT_FOUND); |
467 |
} else if (ndevs == 1) { |
468 |
/* Only one condidate. */ |
469 |
*modp = mod = dev_list[0].modp; |
470 |
*devinfop = dev = dev_list[0].devinfop; |
471 |
return (mod->load(PATH_LOADER_EFI, dev, |
472 |
bufp, bufsize)); |
473 |
} |
474 |
/* Two or more candidate exist. */ |
475 |
status = bs->CreateEvent(EVT_TIMER, 0, 0, NULL, &timer); |
476 |
if (status != EFI_SUCCESS) { |
477 |
printf("Can't allocate timer event.\n"); |
478 |
return (status); |
479 |
} |
480 |
printf(" 0: AutoSelected Partition (Default): 0\n"); |
481 |
for (i = 0; i < ndevs; i++) { |
482 |
if (dev_list[i].devinfop->preferred == TRUE) |
483 |
c = '*'; |
484 |
else |
485 |
c = ' '; |
486 |
printf(" %c%c: %s: %s: %c\n", c, idx2char(i+1), |
487 |
dev_list[i].modp->name, |
488 |
devpath_str(dev_list[i].devinfop->devpath), |
489 |
idx2char(i+1)); |
490 |
} |
491 |
/* One alpha-num selection only. Is this big enough ?? */ |
492 |
bs->SetTimer(timer, TimerPeriodic, 10000000); |
493 |
events[0] = timer; |
494 |
events[1] = conin->WaitForKey; |
495 |
time_left = SELECT_TIMEOUT; |
496 |
|
497 |
while (1) { |
498 |
if (time_left > 0) { |
499 |
printf("Select from 0 to %c. Timeout in %2d seconds," |
500 |
" [Space] to pause : ", |
501 |
idx2char(ndevs), time_left); |
502 |
} |
503 |
status = bs->WaitForEvent(2, events, &idx); |
504 |
if (status != EFI_SUCCESS) { |
505 |
bs->CloseEvent(timer); |
506 |
return (status); |
507 |
} |
508 |
if (idx == 0) { |
509 |
time_left--; |
510 |
if (time_left <=0) { |
511 |
printf("\nTimeout. " |
512 |
"Partition is AutoSelected.\n"); |
513 |
n = 0; |
514 |
break; |
515 |
} else { |
516 |
move_to_tol(); |
517 |
} |
518 |
} |
519 |
if (idx == 1) { |
520 |
c = getchar(); |
521 |
if ((c == '\n') || (c == '\r')) { |
522 |
putchar('\n'); |
523 |
n = 0; |
524 |
break; |
525 |
} else if ((time_left > 0) && (c == ' ')) { |
526 |
bs->SetTimer(timer, TimerCancel, 0); |
527 |
time_left = -1; |
528 |
printf("\nTimer stopeed.\n Please Key in: "); |
529 |
} |
530 |
n = char2idx(c); |
531 |
if ((n >= 0) && (n <= ndevs)) { |
532 |
bs->SetTimer(timer, TimerCancel, 0); |
533 |
time_left = -1; |
534 |
printf("\n %c is selected.\n", c); |
535 |
if (n == 0) { /* AutoSelect */ |
536 |
break; |
537 |
} else { |
538 |
mod = dev_list[n-1].modp; |
539 |
dev = dev_list[n-1].devinfop; |
540 |
status = mod->load(PATH_LOADER_EFI, |
541 |
dev, bufp, bufsize); |
542 |
if (status == EFI_SUCCESS) { |
543 |
break; |
544 |
} |
545 |
printf("Failed to load '%s'\n", |
546 |
PATH_LOADER_EFI); |
547 |
printf("Please select again: "); |
548 |
} |
549 |
} else { |
550 |
/* Invalid charecter. */ |
551 |
move_to_tol(); |
552 |
} |
553 |
} |
554 |
}; |
555 |
bs->CloseEvent(timer); |
556 |
if (n == 0) { /* AutoSelect */ |
557 |
status = load_loader(modp, devinfop, bufp, bufsize, TRUE); |
558 |
if (status != EFI_SUCCESS) { |
559 |
status = load_loader(modp, devinfop, bufp, bufsize, |
560 |
FALSE); |
561 |
} |
562 |
} else { |
563 |
*modp = dev_list[n-1].modp; |
564 |
*devinfop = dev_list[n-1].devinfop; |
565 |
status = EFI_SUCCESS; |
566 |
} |
567 |
return (status); |
568 |
} |
569 |
|
353 |
/* |
570 |
/* |
354 |
* try_boot only returns if it fails to load the loader. If it succeeds |
571 |
* 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. |
572 |
* it simply boots, otherwise it returns the status of last EFI call. |
Lines 358-364
Link Here
|
358 |
try_boot() |
575 |
try_boot() |
359 |
{ |
576 |
{ |
360 |
size_t bufsize, loadersize, cmdsize; |
577 |
size_t bufsize, loadersize, cmdsize; |
361 |
void *buf, *loaderbuf; |
578 |
void *buf = NULL, *loaderbuf = NULL; |
362 |
char *cmd; |
579 |
char *cmd; |
363 |
dev_info_t *dev; |
580 |
dev_info_t *dev; |
364 |
const boot_module_t *mod; |
581 |
const boot_module_t *mod; |
Lines 365-379
Link Here
|
365 |
EFI_HANDLE loaderhandle; |
582 |
EFI_HANDLE loaderhandle; |
366 |
EFI_LOADED_IMAGE *loaded_image; |
583 |
EFI_LOADED_IMAGE *loaded_image; |
367 |
EFI_STATUS status; |
584 |
EFI_STATUS status; |
|
|
585 |
int ndevs; |
368 |
|
586 |
|
369 |
status = load_loader(&mod, &dev, &loaderbuf, &loadersize, TRUE); |
587 |
ndevs = list_devices(); |
|
|
588 |
status = select_bootdev(ndevs, &mod, &dev, &loaderbuf, &loadersize); |
370 |
if (status != EFI_SUCCESS) { |
589 |
if (status != EFI_SUCCESS) { |
371 |
status = load_loader(&mod, &dev, &loaderbuf, &loadersize, |
590 |
printf("Failed to load '%s'\n", PATH_LOADER_EFI); |
372 |
FALSE); |
591 |
return (EFI_NOT_FOUND); |
373 |
if (status != EFI_SUCCESS) { |
|
|
374 |
printf("Failed to load '%s'\n", PATH_LOADER_EFI); |
375 |
return (status); |
376 |
} |
377 |
} |
592 |
} |
378 |
|
593 |
|
379 |
/* |
594 |
/* |
Lines 423-428
Link Here
|
423 |
loaded_image->LoadOptionsSize = cmdsize; |
638 |
loaded_image->LoadOptionsSize = cmdsize; |
424 |
loaded_image->LoadOptions = cmd; |
639 |
loaded_image->LoadOptions = cmd; |
425 |
|
640 |
|
|
|
641 |
printf("Boot from: %s in 1 second\n", devpath_str(dev->devpath)); |
642 |
bs->Stall(1000000); |
643 |
|
426 |
DPRINTF("Starting '%s' in 5 seconds...", PATH_LOADER_EFI); |
644 |
DPRINTF("Starting '%s' in 5 seconds...", PATH_LOADER_EFI); |
427 |
DSTALL(1000000); |
645 |
DSTALL(1000000); |
428 |
DPRINTF("."); |
646 |
DPRINTF("."); |
Lines 559-579
Link Here
|
559 |
DSTALL(500000); |
777 |
DSTALL(500000); |
560 |
} |
778 |
} |
561 |
|
779 |
|
562 |
EFI_STATUS |
780 |
static EFI_STATUS |
563 |
efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE *Xsystab) |
781 |
init_console() |
564 |
{ |
782 |
{ |
565 |
EFI_HANDLE *handles; |
|
|
566 |
EFI_LOADED_IMAGE *img; |
567 |
EFI_DEVICE_PATH *imgpath; |
568 |
EFI_STATUS status; |
783 |
EFI_STATUS status; |
569 |
EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl = NULL; |
784 |
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 |
|
785 |
|
573 |
/* Basic initialization*/ |
786 |
UINTN i, max_dim, best_mode, cols, rows; |
574 |
systab = Xsystab; |
|
|
575 |
image = Ximage; |
576 |
bs = Xsystab->BootServices; |
577 |
|
787 |
|
578 |
/* Set up the console, so printf works. */ |
788 |
/* Set up the console, so printf works. */ |
579 |
status = bs->LocateProtocol(&ConsoleControlGUID, NULL, |
789 |
status = bs->LocateProtocol(&ConsoleControlGUID, NULL, |
Lines 584-591
Link Here
|
584 |
/* |
794 |
/* |
585 |
* Reset the console and find the best text mode. |
795 |
* Reset the console and find the best text mode. |
586 |
*/ |
796 |
*/ |
|
|
797 |
conin = systab->ConIn; |
587 |
conout = systab->ConOut; |
798 |
conout = systab->ConOut; |
|
|
799 |
conin->Reset(conin, TRUE); |
588 |
conout->Reset(conout, TRUE); |
800 |
conout->Reset(conout, TRUE); |
|
|
801 |
|
589 |
max_dim = best_mode = 0; |
802 |
max_dim = best_mode = 0; |
590 |
for (i = 0; ; i++) { |
803 |
for (i = 0; ; i++) { |
591 |
status = conout->QueryMode(conout, i, &cols, &rows); |
804 |
status = conout->QueryMode(conout, i, &cols, &rows); |
Lines 598-606
Link Here
|
598 |
} |
811 |
} |
599 |
if (max_dim > 0) |
812 |
if (max_dim > 0) |
600 |
conout->SetMode(conout, best_mode); |
813 |
conout->SetMode(conout, best_mode); |
|
|
814 |
|
815 |
conout->SetAttribute(conout, EFI_TEXT_ATTR(DEFAULT_FGCOLOR, |
816 |
DEFAULT_BGCOLOR)); |
601 |
conout->EnableCursor(conout, TRUE); |
817 |
conout->EnableCursor(conout, TRUE); |
602 |
conout->ClearScreen(conout); |
818 |
conout->ClearScreen(conout); |
603 |
|
819 |
|
|
|
820 |
return (status); |
821 |
} |
822 |
|
823 |
EFI_STATUS |
824 |
efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE *Xsystab) |
825 |
{ |
826 |
EFI_HANDLE *handles; |
827 |
EFI_LOADED_IMAGE *img; |
828 |
EFI_DEVICE_PATH *imgpath; |
829 |
EFI_STATUS status; |
830 |
UINTN i, hsize, nhandles; |
831 |
|
832 |
/* Basic initialization*/ |
833 |
systab = Xsystab; |
834 |
image = Ximage; |
835 |
bs = Xsystab->BootServices; |
836 |
|
837 |
init_console(); |
838 |
|
604 |
printf("\n>> FreeBSD EFI boot block\n"); |
839 |
printf("\n>> FreeBSD EFI boot block\n"); |
605 |
printf(" Loader path: %s\n\n", PATH_LOADER_EFI); |
840 |
printf(" Loader path: %s\n\n", PATH_LOADER_EFI); |
606 |
printf(" Initializing modules:"); |
841 |
printf(" Initializing modules:"); |
Lines 715-728
Link Here
|
715 |
void |
950 |
void |
716 |
putchar(int c) |
951 |
putchar(int c) |
717 |
{ |
952 |
{ |
|
|
953 |
efi_cons_putchar(c); |
954 |
} |
955 |
|
956 |
void |
957 |
efi_cons_putchar(int c) |
958 |
{ |
718 |
CHAR16 buf[2]; |
959 |
CHAR16 buf[2]; |
719 |
|
960 |
|
720 |
if (c == '\n') { |
961 |
if (c == '\n') { |
721 |
buf[0] = '\r'; |
962 |
buf[0] = '\r'; |
722 |
buf[1] = 0; |
963 |
buf[1] = 0; |
723 |
systab->ConOut->OutputString(systab->ConOut, buf); |
964 |
conout->OutputString(conout, buf); |
724 |
} |
965 |
} |
725 |
buf[0] = c; |
966 |
buf[0] = c; |
726 |
buf[1] = 0; |
967 |
buf[1] = 0; |
727 |
systab->ConOut->OutputString(systab->ConOut, buf); |
968 |
conout->OutputString(conout, buf); |
728 |
} |
969 |
} |
|
|
970 |
|
971 |
int |
972 |
getchar(void) |
973 |
{ |
974 |
return efi_cons_getchar(); |
975 |
} |
976 |
|
977 |
|
978 |
int |
979 |
efi_cons_getchar() |
980 |
{ |
981 |
EFI_INPUT_KEY key; |
982 |
EFI_STATUS status; |
983 |
UINTN junk; |
984 |
|
985 |
/* Try to read a key stroke. We wait for one if none is pending. */ |
986 |
status = conin->ReadKeyStroke(conin, &key); |
987 |
if (status == EFI_NOT_READY) { |
988 |
bs->WaitForEvent(1, &conin->WaitForKey, &junk); |
989 |
status = conin->ReadKeyStroke(conin, &key); |
990 |
} |
991 |
switch (key.ScanCode) { |
992 |
case 0x17: /* ESC */ |
993 |
return (0x1b); /* esc */ |
994 |
} |
995 |
|
996 |
/* this can return */ |
997 |
return (key.UnicodeChar); |
998 |
} |
999 |
|
1000 |
int |
1001 |
efi_cons_poll() |
1002 |
{ |
1003 |
/* This can clear the signaled state. */ |
1004 |
return (bs->CheckEvent(conin->WaitForKey) == EFI_SUCCESS); |
1005 |
} |
1006 |
|