From 2a9f0905f01f51c3f831af471ddfb2cab416e386 Mon Sep 17 00:00:00 2001 From: srs5694 Date: Mon, 5 Nov 2012 14:10:41 -0500 Subject: [PATCH] Improved scan_delay feature & new ability to edit boot options --- NEWS.txt | 8 ++ docs/refind/drivers.html | 2 +- docs/refind/using.html | 4 +- refind/lib.c | 1 - refind/main.c | 10 ++- refind/menu.c | 40 ++++++++- refind/screen.c | 188 ++++++++++++++++++++++++++++++++++++++- refind/screen.h | 5 ++ 8 files changed, 243 insertions(+), 15 deletions(-) diff --git a/NEWS.txt b/NEWS.txt index c0c4b42..c6b4c01 100644 --- a/NEWS.txt +++ b/NEWS.txt @@ -1,6 +1,14 @@ 0.4.7 (??/?/2012): ------------------ +- Added a boot option editor: Pressing the Insert or F2 key from a boot + tag's options menu opens a simple text-mode line editor on which the boot + options may be edited for a one-time boot with altered options. + +- Modified the "scan_delay" feature to delay and then perform a re-scan, + which may work better than the first attempt at this feature (which I'm + told isn't working as planned). + - Modified rEFInd to add a space after the command-line options only when launching Mac OS X. On some early Macs, the extra space (which had been present by default, as a carryover from rEFIt) causes problems when diff --git a/docs/refind/drivers.html b/docs/refind/drivers.html index 3146c02..b61b7c7 100644 --- a/docs/refind/drivers.html +++ b/docs/refind/drivers.html @@ -110,7 +110,7 @@ href="mailto:rodsmith@rodsbooks.com">rodsmith@rodsbooks.com

Note that most of these uses are theoretical, at least to me; I don't know of any specific examples of EFI drivers (available as separate files) for disk controller hardware, network cards, or video cards. Such drivers are often embedded in the firmware of the devices themselves, and should be loaded automatically by the EFI. Chances are good that a few such drivers are available, unknown to me, and more may become available in the future. If you happen to have a device and need support for it under EFI, searching for drivers is certainly worth doing.

-

To the best of my knowledge, the best reason to want EFI driver support in rEFInd is to provide access to filesystems. Although EFI filesystem driver choices are currently limited, those that are available can help to improve your installation and configuration options, particularly if you've found yourself "boxed in" by awkward installation or bugs, such as the dinky ESP that Ubuntu creates by default or the bug that prevents a Linux kernel with EFI stub loader support from booting from the ESP of at least some Macs.

+

To the best of my knowledge, the best reason to want EFI driver support in rEFInd is to provide access to filesystems. Although EFI filesystem driver choices are currently limited, those that are available can help to improve your installation and configuration options, particularly if you've found yourself "boxed in" by awkward installation or bugs, such as the dinky ESP that Ubuntu creates by default or the bug that prevents a Linux kernel with EFI stub loader support from booting from the ESP of at least some Macs.

As a side note, using an ISO-9660 driver can theoretically help you keep the size of a custom Linux boot CD/DVD down to a reasonable value. This is because EFI systems normally boot from optical discs by reading a FAT image file in El Torito format and treating that file as an ESP. If you need to store the kernel both in that file and directly in the ISO-9660 filesystem (to maintain bootability on BIOS systems), that can represent an unwanted extra space requirement. Placing rEFInd and an ISO-9660 driver in the FAT image file should enable you to store the kernel on the disc only once. Unfortunately, this doesn't work in practice. When the ISO-9660 driver is loaded from the El Torito image, the driver discovers that the optical disc is in use and refuses to access it. It's possible to use EFI shell commands to give the ISO-9660 driver access to the shell device, but this causes the El Torito access to go away, which means that anything loaded from the El Torito image (such as rEFInd) is likely to malfunction. Also, some EFI implementations include ISO-9660 drivers, so you might not need a separate ISO-9660 driver if you're building a disc for a particular computer.

diff --git a/docs/refind/using.html b/docs/refind/using.html index 05fba57..44ad81a 100644 --- a/docs/refind/using.html +++ b/docs/refind/using.html @@ -15,7 +15,7 @@ href="mailto:rodsmith@rodsbooks.com">rodsmith@rodsbooks.com

Originally written: 3/14/2012; last Web page update: -10/6/2012, referencing rEFInd 0.4.6

+11/5/2012, referencing rEFInd 0.4.6.3

I'm a technical writer and consultant specializing in Linux technologies. This Web page is provided free of charge and with no annoying outside ads; however, I did take time to prepare it, and Web hosting does cost money. If you find this Web page useful, please consider making a small donation to help keep this site up and running. Thanks!

@@ -181,7 +181,7 @@ href="mailto:rodsmith@rodsbooks.com">rodsmith@rodsbooks.com

Insert, F2, or + - Opens the selection's submenu, which is most useful with Mac OS X, ELILO, and Linux kernels with EFI stub loader support + From the main menu, opens the selection's submenu, which is most useful with Mac OS X, ELILO, and Linux kernels with EFI stub loader support; in a submenu, opens a line editor enabling editing of boot options F10 diff --git a/refind/lib.c b/refind/lib.c index 6fa9e2f..0dd5439 100644 --- a/refind/lib.c +++ b/refind/lib.c @@ -1400,4 +1400,3 @@ BOOLEAN EjectMedia(VOID) { MyFreePool(Handles); return (Ejected > 0); } // VOID EjectMedia() - diff --git a/refind/main.c b/refind/main.c index a8ecdf3..0d1ca70 100644 --- a/refind/main.c +++ b/refind/main.c @@ -115,7 +115,7 @@ static VOID AboutrEFInd(VOID) if (AboutMenu.EntryCount == 0) { AboutMenu.TitleImage = BuiltinIcon(BUILTIN_ICON_FUNC_ABOUT); - AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.4.6.2"); + AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.4.6.3"); AddMenuInfoLine(&AboutMenu, L""); AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2006-2010 Christoph Pfisterer"); AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2012 Roderick W. Smith"); @@ -1831,6 +1831,10 @@ efi_main (IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable) // further bootstrap (now with config available) SetupScreen(); + LoadDrivers(); + ScanForBootloaders(); + ScanForTools(); + if (GlobalConfig.ScanDelay > 0) { BGColor.b = 255; BGColor.g = 175; @@ -1839,10 +1843,8 @@ efi_main (IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable) egDisplayMessage(L"Pausing before disk scan; please wait....", &BGColor); for (i = 0; i < GlobalConfig.ScanDelay; i++) refit_call1_wrapper(BS->Stall, 1000000); + RescanAll(); } // if - LoadDrivers(); - ScanForBootloaders(); - ScanForTools(); Selection = StrDuplicate(GlobalConfig.DefaultSelection); while (MainLoopRunning) { diff --git a/refind/menu.c b/refind/menu.c index 700f7d8..ba1f78d 100644 --- a/refind/menu.c +++ b/refind/menu.c @@ -486,7 +486,7 @@ static UINTN RunGenericMenu(IN REFIT_MENU_SCREEN *Screen, IN MENU_STYLE_FUNC Sty if (ChosenEntry) *ChosenEntry = Screen->Entries[State.CurrentSelection]; return MenuExit; -} /* static UINTN RunGenericMenu( */ +} /* static UINTN RunGenericMenu() */ // // text-mode generic style @@ -705,7 +705,7 @@ static VOID GraphicsMenuStyle(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *Sta break; } -} +} // static VOID GraphicsMenuStyle() // // graphical main menu style @@ -901,7 +901,37 @@ VOID MainMenuStyle(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State, IN UINT break; } -} +} // VOID MainMenuStyle() + +// Enable the user to edit boot loader options. +// Returns TRUE if the user exited with edited options; FALSE if the user +// pressed Esc to terminate the edit. +static BOOLEAN EditOptions(LOADER_ENTRY *MenuEntry) { + UINTN x_max, y_max; + CHAR16 *EditedOptions; + CHAR16 message[] = L"Use cursor keys to edit, Esc to exit, Enter to boot with edited options"; + EG_PIXEL DarkBackgroundPixel = { 0x0, 0x0, 0x0, 0 }; + BOOLEAN retval = FALSE; + + refit_call4_wrapper(ST->ConOut->QueryMode, ST->ConOut, ST->ConOut->Mode->Mode, &x_max, &y_max); + + if (!GlobalConfig.TextOnly) + SwitchToText(TRUE); + + egClearScreen(&DarkBackgroundPixel); + + refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 0, y_max - 1); + refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, message); + + if (line_edit(MenuEntry->LoadOptions, &EditedOptions, x_max, 1)) { + MyFreePool(MenuEntry->LoadOptions); + MenuEntry->LoadOptions = EditedOptions; + retval = TRUE; + } // if + if (!GlobalConfig.TextOnly) + SwitchToGraphics(); + return retval; +} // VOID EditOptions() // // user-callable dispatcher functions @@ -944,6 +974,10 @@ UINTN RunMainMenu(IN REFIT_MENU_SCREEN *Screen, IN CHAR16* DefaultSelection, OUT MenuExit = RunGenericMenu(TempChosenEntry->SubScreen, Style, -1, &TempChosenEntry); if (MenuExit == MENU_EXIT_ESCAPE || TempChosenEntry->Tag == TAG_RETURN) MenuExit = 0; + if (MenuExit == MENU_EXIT_DETAILS) { + if (!EditOptions((LOADER_ENTRY *) TempChosenEntry)) + MenuExit = 0; + } // if } } diff --git a/refind/screen.c b/refind/screen.c index 3b98586..e1154ff 100644 --- a/refind/screen.c +++ b/refind/screen.c @@ -48,8 +48,6 @@ UINTN ConWidth; UINTN ConHeight; CHAR16 *BlankLine; -static VOID SwitchToText(IN BOOLEAN CursorEnabled); -static VOID SwitchToGraphics(VOID); static VOID DrawScreenHeader(IN CHAR16 *Title); // UGA defines and variables @@ -127,13 +125,13 @@ VOID SetupScreen(VOID) } } -static VOID SwitchToText(IN BOOLEAN CursorEnabled) +VOID SwitchToText(IN BOOLEAN CursorEnabled) { egSetGraphicsModeEnabled(FALSE); refit_call2_wrapper(ST->ConOut->EnableCursor, ST->ConOut, CursorEnabled); } -static VOID SwitchToGraphics(VOID) +VOID SwitchToGraphics(VOID) { if (AllowGraphicsMode && !egIsGraphicsModeEnabled()) { egSetGraphicsModeEnabled(TRUE); @@ -497,3 +495,185 @@ VOID BltImageCompositeBadge(IN EG_IMAGE *BaseImage, IN EG_IMAGE *TopImage, IN EG egFreeImage(CompImage); GraphicsScreenDirty = TRUE; } + +// Line-editing functions borrowed from gummiboot (cursor_left(), cursor_right(), & line_edit()) + +static void cursor_left(UINTN *cursor, UINTN *first) +{ + if ((*cursor) > 0) + (*cursor)--; + else if ((*first) > 0) + (*first)--; +} + +static void cursor_right(UINTN *cursor, UINTN *first, UINTN x_max, UINTN len) +{ + if ((*cursor)+2 < x_max) + (*cursor)++; + else if ((*first) + (*cursor) < len) + (*first)++; +} + +BOOLEAN line_edit(CHAR16 *line_in, CHAR16 **line_out, UINTN x_max, UINTN y_pos) { + CHAR16 *line; + UINTN size; + UINTN len; + UINTN first; + CHAR16 *print; + UINTN cursor; + BOOLEAN exit; + BOOLEAN enter; + + if (!line_in) + line_in = L""; + size = StrLen(line_in) + 1024; + line = AllocatePool(size * sizeof(CHAR16)); + StrCpy(line, line_in); + len = StrLen(line); + print = AllocatePool(x_max * sizeof(CHAR16)); + + refit_call2_wrapper(ST->ConOut->EnableCursor, ST->ConOut, TRUE); + + first = 0; + cursor = 0; + enter = FALSE; + exit = FALSE; + while (!exit) { + UINTN index; + EFI_STATUS err; + EFI_INPUT_KEY key; + UINTN i; + + i = len - first; + if (i >= x_max-2) + i = x_max-2; + CopyMem(print, line + first, i * sizeof(CHAR16)); + print[i++] = ' '; + print[i] = '\0'; + + refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 0, y_pos); + refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, print); + refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, cursor, y_pos); + + refit_call3_wrapper(BS->WaitForEvent, 1, &ST->ConIn->WaitForKey, &index); + err = refit_call2_wrapper(ST->ConIn->ReadKeyStroke, ST->ConIn, &key); + if (EFI_ERROR(err)) + continue; + + switch (key.ScanCode) { + case SCAN_ESC: + exit = TRUE; + break; + case SCAN_HOME: + cursor = 0; + first = 0; + continue; + case SCAN_END: + cursor = len; + if (cursor >= x_max) { + cursor = x_max-2; + first = len - (x_max-2); + } + continue; + case SCAN_UP: + while((first + cursor) && line[first + cursor] == ' ') + cursor_left(&cursor, &first); + while((first + cursor) && line[first + cursor] != ' ') + cursor_left(&cursor, &first); + while((first + cursor) && line[first + cursor] == ' ') + cursor_left(&cursor, &first); + if (first + cursor != len && first + cursor) + cursor_right(&cursor, &first, x_max, len); + refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, cursor, y_pos); + continue; + case SCAN_DOWN: + while(line[first + cursor] && line[first + cursor] == ' ') + cursor_right(&cursor, &first, x_max, len); + while(line[first + cursor] && line[first + cursor] != ' ') + cursor_right(&cursor, &first, x_max, len); + while(line[first + cursor] && line[first + cursor] == ' ') + cursor_right(&cursor, &first, x_max, len); + refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, cursor, y_pos); + continue; + case SCAN_RIGHT: + if (first + cursor == len) + continue; + cursor_right(&cursor, &first, x_max, len); + refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, cursor, y_pos); + continue; + case SCAN_LEFT: + cursor_left(&cursor, &first); + refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, cursor, y_pos); + continue; + case SCAN_DELETE: + if (len == 0) + continue; + if (first + cursor == len) + continue; + for (i = first + cursor; i < len; i++) + line[i] = line[i+1]; + line[len-1] = ' '; + len--; + continue; + } + + switch (key.UnicodeChar) { + case CHAR_LINEFEED: + case CHAR_CARRIAGE_RETURN: + if (StrCmp(line, line_in) != 0) { + *line_out = line; + line = NULL; + } + enter = TRUE; + exit = TRUE; + break; + case CHAR_BACKSPACE: + if (len == 0) + continue; + if (first == 0 && cursor == 0) + continue; + for (i = first + cursor-1; i < len; i++) + line[i] = line[i+1]; + len--; + if (cursor > 0) + cursor--; + if (cursor > 0 || first == 0) + continue; + /* show full line if it fits */ + if (len < x_max-2) { + cursor = first; + first = 0; + continue; + } + /* jump left to see what we delete */ + if (first > 10) { + first -= 10; + cursor = 10; + } else { + cursor = first; + first = 0; + } + continue; + case '\t': + case ' ' ... '~': + case 0x80 ... 0xffff: + if (len+1 == size) + continue; + for (i = len; i > first + cursor; i--) + line[i] = line[i-1]; + line[first + cursor] = key.UnicodeChar; + len++; + line[len] = '\0'; + if (cursor+2 < x_max) + cursor++; + else if (first + cursor < len) + first++; + continue; + } + } + + refit_call2_wrapper(ST->ConOut->EnableCursor, ST->ConOut, FALSE); + FreePool(print); + FreePool(line); + return enter; +} /* BOOLEAN line_edit() */ diff --git a/refind/screen.h b/refind/screen.h index d0ffa29..b89fe8f 100644 --- a/refind/screen.h +++ b/refind/screen.h @@ -95,6 +95,9 @@ VOID PauseForKey(VOID); BOOLEAN CheckFatalError(IN EFI_STATUS Status, IN CHAR16 *where); BOOLEAN CheckError(IN EFI_STATUS Status, IN CHAR16 *where); +VOID SwitchToText(IN BOOLEAN CursorEnabled); +VOID SwitchToGraphics(VOID); + VOID SwitchToGraphicsAndClear(VOID); VOID BltClearScreen(IN BOOLEAN ShowBanner); VOID BltImage(IN EG_IMAGE *Image, IN UINTN XPos, IN UINTN YPos); @@ -102,4 +105,6 @@ VOID BltImageAlpha(IN EG_IMAGE *Image, IN UINTN XPos, IN UINTN YPos, IN EG_PIXEL //VOID BltImageComposite(IN EG_IMAGE *BaseImage, IN EG_IMAGE *TopImage, IN UINTN XPos, IN UINTN YPos); VOID BltImageCompositeBadge(IN EG_IMAGE *BaseImage, IN EG_IMAGE *TopImage, IN EG_IMAGE *BadgeImage, IN UINTN XPos, IN UINTN YPos); +BOOLEAN line_edit(CHAR16 *line_in, CHAR16 **line_out, UINTN x_max, UINTN y_pos); + #endif -- 2.39.2