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-52
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); |
51 |
EFI_STATUS efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE* Xsystab); |
55 |
EFI_STATUS efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE* Xsystab); |
52 |
|
56 |
|
Lines 53-64
Link Here
|
53 |
EFI_SYSTEM_TABLE *systab; |
57 |
EFI_SYSTEM_TABLE *systab; |
54 |
EFI_BOOT_SERVICES *bs; |
58 |
EFI_BOOT_SERVICES *bs; |
55 |
static EFI_HANDLE *image; |
59 |
static EFI_HANDLE *image; |
|
|
60 |
static SIMPLE_TEXT_OUTPUT_INTERFACE *conout; |
61 |
static SIMPLE_INPUT_INTERFACE *conin; |
56 |
|
62 |
|
57 |
static EFI_GUID BlockIoProtocolGUID = BLOCK_IO_PROTOCOL; |
63 |
static EFI_GUID BlockIoProtocolGUID = BLOCK_IO_PROTOCOL; |
58 |
static EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL; |
64 |
static EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL; |
59 |
static EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL; |
65 |
static EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL; |
60 |
static EFI_GUID ConsoleControlGUID = EFI_CONSOLE_CONTROL_PROTOCOL_GUID; |
|
|
61 |
|
66 |
|
|
|
67 |
#define DEFAULT_FGCOLOR EFI_LIGHTGRAY |
68 |
#define DEFAULT_BGCOLOR EFI_BLACK |
69 |
|
62 |
/* |
70 |
/* |
63 |
* Provide Malloc / Free backed by EFIs AllocatePool / FreePool which ensures |
71 |
* Provide Malloc / Free backed by EFIs AllocatePool / FreePool which ensures |
64 |
* memory is correctly aligned avoiding EFI_INVALID_PARAMETER returns from |
72 |
* memory is correctly aligned avoiding EFI_INVALID_PARAMETER returns from |
Lines 350-355
Link Here
|
350 |
return (EFI_NOT_FOUND); |
358 |
return (EFI_NOT_FOUND); |
351 |
} |
359 |
} |
352 |
|
360 |
|
|
|
361 |
/* quick dirty work. */ |
362 |
#define NUM_DEV_LIST 10 |
363 |
|
364 |
static struct dev_list_t { |
365 |
const boot_module_t *modp; |
366 |
dev_info_t *devinfop; |
367 |
} dev_list[NUM_DEV_LIST]; |
368 |
|
369 |
static int |
370 |
list_devices(void) |
371 |
{ |
372 |
UINTN i, j; |
373 |
dev_info_t *dev; |
374 |
const boot_module_t *mod; |
375 |
|
376 |
j = 0; |
377 |
for (i = 0; i < NUM_BOOT_MODULES; i++) { |
378 |
if (boot_modules[i] == NULL) |
379 |
continue; |
380 |
mod = boot_modules[i]; |
381 |
for (dev = mod->devices(); dev != NULL; dev = dev->next) { |
382 |
dev_list[j].devinfop = dev; |
383 |
dev_list[j].modp = mod; |
384 |
j++; |
385 |
if (j >= NUM_DEV_LIST) |
386 |
break; |
387 |
} |
388 |
} |
389 |
|
390 |
return (j); |
391 |
} |
392 |
|
393 |
static int |
394 |
select_dev(int ndevs) |
395 |
{ |
396 |
int i; |
397 |
int c; |
398 |
|
399 |
for (i = 0; i < ndevs; i++) { |
400 |
if (dev_list[i].devinfop->preferred == TRUE) |
401 |
c = '*'; |
402 |
else |
403 |
c = ' '; |
404 |
printf(" %c%d: %s: %s\n", c, i, dev_list[i].modp->name, |
405 |
devpath_str(dev_list[i].devinfop->devpath)); |
406 |
} |
407 |
/* One digit selection only. Is this big enough ?? */ |
408 |
printf("Select from 0 to %d: ", ndevs - 1); |
409 |
while (1) { |
410 |
c = getchar(); |
411 |
i = (c - '0') & 0xff; |
412 |
if ((i >= 0) && (i < ndevs)) { |
413 |
return (i); |
414 |
} |
415 |
printf("\nInvalid num. Try again: "); |
416 |
} |
417 |
} |
418 |
|
353 |
/* |
419 |
/* |
354 |
* try_boot only returns if it fails to load the loader. If it succeeds |
420 |
* 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. |
421 |
* it simply boots, otherwise it returns the status of last EFI call. |
Lines 358-364
Link Here
|
358 |
try_boot() |
424 |
try_boot() |
359 |
{ |
425 |
{ |
360 |
size_t bufsize, loadersize, cmdsize; |
426 |
size_t bufsize, loadersize, cmdsize; |
361 |
void *buf, *loaderbuf; |
427 |
void *buf = NULL, *loaderbuf = NULL; |
362 |
char *cmd; |
428 |
char *cmd; |
363 |
dev_info_t *dev; |
429 |
dev_info_t *dev; |
364 |
const boot_module_t *mod; |
430 |
const boot_module_t *mod; |
Lines 365-381
Link Here
|
365 |
EFI_HANDLE loaderhandle; |
431 |
EFI_HANDLE loaderhandle; |
366 |
EFI_LOADED_IMAGE *loaded_image; |
432 |
EFI_LOADED_IMAGE *loaded_image; |
367 |
EFI_STATUS status; |
433 |
EFI_STATUS status; |
|
|
434 |
int i, ndevs; |
368 |
|
435 |
|
369 |
status = load_loader(&mod, &dev, &loaderbuf, &loadersize, TRUE); |
436 |
ndevs = list_devices(); |
370 |
if (status != EFI_SUCCESS) { |
437 |
if (ndevs == 0) { |
|
|
438 |
printf("Failed to load '%s'\n", PATH_LOADER_EFI); |
439 |
return (EFI_NOT_FOUND); |
440 |
} else if (ndevs == 1) { |
441 |
mod = dev_list[0].modp; |
442 |
dev = dev_list[0].devinfop; |
371 |
status = load_loader(&mod, &dev, &loaderbuf, &loadersize, |
443 |
status = load_loader(&mod, &dev, &loaderbuf, &loadersize, |
372 |
FALSE); |
444 |
dev_list[0].devinfop->preferred); |
373 |
if (status != EFI_SUCCESS) { |
445 |
if (status != EFI_SUCCESS) { |
374 |
printf("Failed to load '%s'\n", PATH_LOADER_EFI); |
446 |
printf("Failed to load '%s'\n", PATH_LOADER_EFI); |
375 |
return (status); |
447 |
return (status); |
376 |
} |
448 |
} |
|
|
449 |
} else { |
450 |
while (1) { |
451 |
i = select_dev(ndevs); |
452 |
printf(" %d is selected.\n", i); |
453 |
mod = dev_list[i].modp; |
454 |
dev = dev_list[i].devinfop; |
455 |
status = mod->load(PATH_LOADER_EFI, dev, |
456 |
&loaderbuf, &loadersize); |
457 |
if (status == EFI_SUCCESS) |
458 |
break; |
459 |
printf("Failed to load '%s'\n", PATH_LOADER_EFI); |
460 |
printf("Please select again.\n"); |
461 |
} |
377 |
} |
462 |
} |
378 |
|
463 |
|
|
|
464 |
printf("Boot from: %s\n", devpath_str(dev->devpath)); |
465 |
|
379 |
/* |
466 |
/* |
380 |
* Read in and parse the command line from /boot.config or /boot/config, |
467 |
* 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 |
468 |
* if present. We'll pass it the next stage via a simple ASCII |
Lines 423-428
Link Here
|
423 |
loaded_image->LoadOptionsSize = cmdsize; |
510 |
loaded_image->LoadOptionsSize = cmdsize; |
424 |
loaded_image->LoadOptions = cmd; |
511 |
loaded_image->LoadOptions = cmd; |
425 |
|
512 |
|
|
|
513 |
printf("Press ANY key to boot\n"); |
514 |
getchar(); |
515 |
|
426 |
DPRINTF("Starting '%s' in 5 seconds...", PATH_LOADER_EFI); |
516 |
DPRINTF("Starting '%s' in 5 seconds...", PATH_LOADER_EFI); |
427 |
DSTALL(1000000); |
517 |
DSTALL(1000000); |
428 |
DPRINTF("."); |
518 |
DPRINTF("."); |
Lines 559-591
Link Here
|
559 |
DSTALL(500000); |
649 |
DSTALL(500000); |
560 |
} |
650 |
} |
561 |
|
651 |
|
562 |
EFI_STATUS |
652 |
static EFI_STATUS |
563 |
efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE *Xsystab) |
653 |
init_console() |
564 |
{ |
654 |
{ |
565 |
EFI_HANDLE *handles; |
|
|
566 |
EFI_LOADED_IMAGE *img; |
567 |
EFI_DEVICE_PATH *imgpath; |
568 |
EFI_STATUS status; |
655 |
EFI_STATUS status; |
569 |
EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl = NULL; |
656 |
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 |
|
657 |
|
573 |
/* Basic initialization*/ |
|
|
574 |
systab = Xsystab; |
575 |
image = Ximage; |
576 |
bs = Xsystab->BootServices; |
577 |
|
578 |
/* Set up the console, so printf works. */ |
658 |
/* 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 |
/* |
659 |
/* |
585 |
* Reset the console and find the best text mode. |
660 |
* Reset the console and find the best text mode. |
586 |
*/ |
661 |
*/ |
|
|
662 |
conin = systab->ConIn; |
587 |
conout = systab->ConOut; |
663 |
conout = systab->ConOut; |
|
|
664 |
conin->Reset(conin, TRUE); |
588 |
conout->Reset(conout, TRUE); |
665 |
conout->Reset(conout, TRUE); |
|
|
666 |
|
589 |
max_dim = best_mode = 0; |
667 |
max_dim = best_mode = 0; |
590 |
for (i = 0; ; i++) { |
668 |
for (i = 0; ; i++) { |
591 |
status = conout->QueryMode(conout, i, &cols, &rows); |
669 |
status = conout->QueryMode(conout, i, &cols, &rows); |
Lines 598-606
Link Here
|
598 |
} |
676 |
} |
599 |
if (max_dim > 0) |
677 |
if (max_dim > 0) |
600 |
conout->SetMode(conout, best_mode); |
678 |
conout->SetMode(conout, best_mode); |
|
|
679 |
|
680 |
conout->SetAttribute(conout, EFI_TEXT_ATTR(DEFAULT_FGCOLOR, |
681 |
DEFAULT_BGCOLOR)); |
601 |
conout->EnableCursor(conout, TRUE); |
682 |
conout->EnableCursor(conout, TRUE); |
602 |
conout->ClearScreen(conout); |
683 |
conout->ClearScreen(conout); |
603 |
|
684 |
|
|
|
685 |
return (status); |
686 |
} |
687 |
|
688 |
EFI_STATUS |
689 |
efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE *Xsystab) |
690 |
{ |
691 |
EFI_HANDLE *handles; |
692 |
EFI_LOADED_IMAGE *img; |
693 |
EFI_DEVICE_PATH *imgpath; |
694 |
EFI_STATUS status; |
695 |
UINTN i, hsize, nhandles; |
696 |
|
697 |
/* Basic initialization*/ |
698 |
systab = Xsystab; |
699 |
image = Ximage; |
700 |
bs = Xsystab->BootServices; |
701 |
|
702 |
init_console(); |
703 |
|
604 |
printf("\n>> FreeBSD EFI boot block\n"); |
704 |
printf("\n>> FreeBSD EFI boot block\n"); |
605 |
printf(" Loader path: %s\n\n", PATH_LOADER_EFI); |
705 |
printf(" Loader path: %s\n\n", PATH_LOADER_EFI); |
606 |
printf(" Initializing modules:"); |
706 |
printf(" Initializing modules:"); |
Lines 715-728
Link Here
|
715 |
void |
815 |
void |
716 |
putchar(int c) |
816 |
putchar(int c) |
717 |
{ |
817 |
{ |
|
|
818 |
efi_cons_putchar(c); |
819 |
} |
820 |
|
821 |
void |
822 |
efi_cons_putchar(int c) |
823 |
{ |
718 |
CHAR16 buf[2]; |
824 |
CHAR16 buf[2]; |
719 |
|
825 |
|
720 |
if (c == '\n') { |
826 |
if (c == '\n') { |
721 |
buf[0] = '\r'; |
827 |
buf[0] = '\r'; |
722 |
buf[1] = 0; |
828 |
buf[1] = 0; |
723 |
systab->ConOut->OutputString(systab->ConOut, buf); |
829 |
conout->OutputString(conout, buf); |
724 |
} |
830 |
} |
725 |
buf[0] = c; |
831 |
buf[0] = c; |
726 |
buf[1] = 0; |
832 |
buf[1] = 0; |
727 |
systab->ConOut->OutputString(systab->ConOut, buf); |
833 |
conout->OutputString(conout, buf); |
728 |
} |
834 |
} |
|
|
835 |
|
836 |
int |
837 |
getchar(void) |
838 |
{ |
839 |
return efi_cons_getchar(); |
840 |
} |
841 |
|
842 |
|
843 |
int |
844 |
efi_cons_getchar() |
845 |
{ |
846 |
EFI_INPUT_KEY key; |
847 |
EFI_STATUS status; |
848 |
UINTN junk; |
849 |
|
850 |
/* Try to read a key stroke. We wait for one if none is pending. */ |
851 |
status = conin->ReadKeyStroke(conin, &key); |
852 |
if (status == EFI_NOT_READY) { |
853 |
bs->WaitForEvent(1, &conin->WaitForKey, &junk); |
854 |
status = conin->ReadKeyStroke(conin, &key); |
855 |
} |
856 |
switch (key.ScanCode) { |
857 |
case 0x17: /* ESC */ |
858 |
return (0x1b); /* esc */ |
859 |
} |
860 |
|
861 |
/* this can return */ |
862 |
return (key.UnicodeChar); |
863 |
} |
864 |
|
865 |
int |
866 |
efi_cons_poll() |
867 |
{ |
868 |
/* This can clear the signaled state. */ |
869 |
return (bs->CheckEvent(conin->WaitForKey) == EFI_SUCCESS); |
870 |
} |
871 |
|