Index: sys/boot/efi/boot1/boot1.c =================================================================== --- sys/boot/efi/boot1/boot1.c (revision 295683) +++ sys/boot/efi/boot1/boot1.c (working copy) @@ -28,7 +28,7 @@ #include #include -#include +#include #include "boot_module.h" #include "paths.h" @@ -47,6 +47,10 @@ /* The initial number of handles used to query EFI for partitions. */ #define NUM_HANDLES_INIT 24 +void efi_cons_putchar(int); +int efi_cons_getchar(void); +int efi_cons_poll(void); +int getchar(void); void putchar(int c); EFI_STATUS efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE* Xsystab); @@ -53,12 +57,16 @@ EFI_SYSTEM_TABLE *systab; EFI_BOOT_SERVICES *bs; static EFI_HANDLE *image; +static SIMPLE_TEXT_OUTPUT_INTERFACE *conout; +static SIMPLE_INPUT_INTERFACE *conin; static EFI_GUID BlockIoProtocolGUID = BLOCK_IO_PROTOCOL; static EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL; static EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL; -static EFI_GUID ConsoleControlGUID = EFI_CONSOLE_CONTROL_PROTOCOL_GUID; +#define DEFAULT_FGCOLOR EFI_LIGHTGRAY +#define DEFAULT_BGCOLOR EFI_BLACK + /* * Provide Malloc / Free backed by EFIs AllocatePool / FreePool which ensures * memory is correctly aligned avoiding EFI_INVALID_PARAMETER returns from @@ -350,6 +358,64 @@ return (EFI_NOT_FOUND); } +/* quick dirty work. */ +#define NUM_DEV_LIST 10 + +static struct dev_list_t { + const boot_module_t *modp; + dev_info_t *devinfop; +} dev_list[NUM_DEV_LIST]; + +static int +list_devices(void) +{ + UINTN i, j; + dev_info_t *dev; + const boot_module_t *mod; + + j = 0; + for (i = 0; i < NUM_BOOT_MODULES; i++) { + if (boot_modules[i] == NULL) + continue; + mod = boot_modules[i]; + for (dev = mod->devices(); dev != NULL; dev = dev->next) { + dev_list[j].devinfop = dev; + dev_list[j].modp = mod; + j++; + if (j >= NUM_DEV_LIST) + break; + } + } + + return (j); +} + +static int +select_dev(int ndevs) +{ + int i; + int c; + + for (i = 0; i < ndevs; i++) { + if (dev_list[i].devinfop->preferred == TRUE) + c = '*'; + else + c = ' '; + printf(" %c%d: %s: %s\n", c, i, dev_list[i].modp->name, + devpath_str(dev_list[i].devinfop->devpath)); + } + /* One digit selection only. Is this big enough ?? */ + printf("Select from 0 to %d: ", ndevs - 1); + while (1) { + c = getchar(); + i = (c - '0') & 0xff; + if ((i >= 0) && (i < ndevs)) { + return (i); + } + printf("\nInvalid num. Try again: "); + } +} + /* * try_boot only returns if it fails to load the loader. If it succeeds * it simply boots, otherwise it returns the status of last EFI call. @@ -358,7 +424,7 @@ try_boot() { size_t bufsize, loadersize, cmdsize; - void *buf, *loaderbuf; + void *buf = NULL, *loaderbuf = NULL; char *cmd; dev_info_t *dev; const boot_module_t *mod; @@ -365,17 +431,38 @@ EFI_HANDLE loaderhandle; EFI_LOADED_IMAGE *loaded_image; EFI_STATUS status; + int i, ndevs; - status = load_loader(&mod, &dev, &loaderbuf, &loadersize, TRUE); - if (status != EFI_SUCCESS) { + ndevs = list_devices(); + if (ndevs == 0) { + printf("Failed to load '%s'\n", PATH_LOADER_EFI); + return (EFI_NOT_FOUND); + } else if (ndevs == 1) { + mod = dev_list[0].modp; + dev = dev_list[0].devinfop; status = load_loader(&mod, &dev, &loaderbuf, &loadersize, - FALSE); + dev_list[0].devinfop->preferred); if (status != EFI_SUCCESS) { printf("Failed to load '%s'\n", PATH_LOADER_EFI); return (status); } + } else { + while (1) { + i = select_dev(ndevs); + printf(" %d is selected.\n", i); + mod = dev_list[i].modp; + dev = dev_list[i].devinfop; + status = mod->load(PATH_LOADER_EFI, dev, + &loaderbuf, &loadersize); + if (status == EFI_SUCCESS) + break; + printf("Failed to load '%s'\n", PATH_LOADER_EFI); + printf("Please select again.\n"); + } } + printf("Boot from: %s\n", devpath_str(dev->devpath)); + /* * Read in and parse the command line from /boot.config or /boot/config, * if present. We'll pass it the next stage via a simple ASCII @@ -423,6 +510,9 @@ loaded_image->LoadOptionsSize = cmdsize; loaded_image->LoadOptions = cmd; + printf("Press ANY key to boot\n"); + getchar(); + DPRINTF("Starting '%s' in 5 seconds...", PATH_LOADER_EFI); DSTALL(1000000); DPRINTF("."); @@ -559,33 +649,21 @@ DSTALL(500000); } -EFI_STATUS -efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE *Xsystab) +static EFI_STATUS +init_console() { - EFI_HANDLE *handles; - EFI_LOADED_IMAGE *img; - EFI_DEVICE_PATH *imgpath; EFI_STATUS status; - EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl = NULL; - SIMPLE_TEXT_OUTPUT_INTERFACE *conout = NULL; - UINTN i, max_dim, best_mode, cols, rows, hsize, nhandles; + UINTN i, max_dim, best_mode, cols, rows; - /* Basic initialization*/ - systab = Xsystab; - image = Ximage; - bs = Xsystab->BootServices; - /* Set up the console, so printf works. */ - status = bs->LocateProtocol(&ConsoleControlGUID, NULL, - (VOID **)&ConsoleControl); - if (status == EFI_SUCCESS) - (void)ConsoleControl->SetMode(ConsoleControl, - EfiConsoleControlScreenText); /* * Reset the console and find the best text mode. */ + conin = systab->ConIn; conout = systab->ConOut; + conin->Reset(conin, TRUE); conout->Reset(conout, TRUE); + max_dim = best_mode = 0; for (i = 0; ; i++) { status = conout->QueryMode(conout, i, &cols, &rows); @@ -598,9 +676,31 @@ } if (max_dim > 0) conout->SetMode(conout, best_mode); + + conout->SetAttribute(conout, EFI_TEXT_ATTR(DEFAULT_FGCOLOR, + DEFAULT_BGCOLOR)); conout->EnableCursor(conout, TRUE); conout->ClearScreen(conout); + return (status); +} + +EFI_STATUS +efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE *Xsystab) +{ + EFI_HANDLE *handles; + EFI_LOADED_IMAGE *img; + EFI_DEVICE_PATH *imgpath; + EFI_STATUS status; + UINTN i, hsize, nhandles; + + /* Basic initialization*/ + systab = Xsystab; + image = Ximage; + bs = Xsystab->BootServices; + + init_console(); + printf("\n>> FreeBSD EFI boot block\n"); printf(" Loader path: %s\n\n", PATH_LOADER_EFI); printf(" Initializing modules:"); @@ -715,14 +815,57 @@ void putchar(int c) { + efi_cons_putchar(c); +} + +void +efi_cons_putchar(int c) +{ CHAR16 buf[2]; if (c == '\n') { buf[0] = '\r'; buf[1] = 0; - systab->ConOut->OutputString(systab->ConOut, buf); + conout->OutputString(conout, buf); } buf[0] = c; buf[1] = 0; - systab->ConOut->OutputString(systab->ConOut, buf); + conout->OutputString(conout, buf); } + +int +getchar(void) +{ + return efi_cons_getchar(); +} + + +int +efi_cons_getchar() +{ + EFI_INPUT_KEY key; + EFI_STATUS status; + UINTN junk; + + /* Try to read a key stroke. We wait for one if none is pending. */ + status = conin->ReadKeyStroke(conin, &key); + if (status == EFI_NOT_READY) { + bs->WaitForEvent(1, &conin->WaitForKey, &junk); + status = conin->ReadKeyStroke(conin, &key); + } + switch (key.ScanCode) { + case 0x17: /* ESC */ + return (0x1b); /* esc */ + } + + /* this can return */ + return (key.UnicodeChar); +} + +int +efi_cons_poll() +{ + /* This can clear the signaled state. */ + return (bs->CheckEvent(conin->WaitForKey) == EFI_SUCCESS); +} +