From a382952f8255863116dde495f0b1eaf9925287a0 Mon Sep 17 00:00:00 2001 From: Ruiyu Ni Date: Wed, 6 May 2015 04:49:30 +0000 Subject: MdeModulePkg: Add BootManagerMenuApp. BootManagerMenuApp only provides a very simple UI showing all the boot options recorded by "BootOrder" and user can select any of them to boot. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ruiyu Ni Reviewed-by: Eric Dong git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@17329 6f19259b-4bc3-4df7-8a09-765794883524 --- .../BootManagerMenuApp/BootManagerMenu.c | 1041 ++++++++++++++++++++ .../BootManagerMenuApp/BootManagerMenu.h | 60 ++ .../BootManagerMenuApp/BootManagerMenuApp.inf | 60 ++ .../BootManagerMenuApp/BootManagerMenuStrings.uni | Bin 0 -> 2756 bytes MdeModulePkg/MdeModulePkg.dsc | 1 + 5 files changed, 1162 insertions(+) create mode 100644 MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenu.c create mode 100644 MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenu.h create mode 100644 MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenuApp.inf create mode 100644 MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenuStrings.uni diff --git a/MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenu.c b/MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenu.c new file mode 100644 index 0000000000..c5a35c070f --- /dev/null +++ b/MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenu.c @@ -0,0 +1,1041 @@ +/** @file + The application to show the Boot Manager Menu. + +Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "BootManagerMenu.h" + +EFI_HII_HANDLE gStringPackHandle; + +BOOLEAN mModeInitialized = FALSE; + +// +// Boot video resolution and text mode. +// +UINT32 mBootHorizontalResolution = 0; +UINT32 mBootVerticalResolution = 0; +UINT32 mBootTextModeColumn = 0; +UINT32 mBootTextModeRow = 0; +// +// BIOS setup video resolution and text mode. +// +UINT32 mSetupTextModeColumn = 0; +UINT32 mSetupTextModeRow = 0; +UINT32 mSetupHorizontalResolution = 0; +UINT32 mSetupVerticalResolution = 0; + +/** + Prints a unicode string to the default console, at + the supplied cursor position, using L"%s" format. + + @param Column The cursor position to print the string at. + @param Row The cursor position to print the string at + @param String String pointer. + + @return Length of string printed to the console + +**/ +UINTN +PrintStringAt ( + IN UINTN Column, + IN UINTN Row, + IN CHAR16 *String + ) +{ + + gST->ConOut->SetCursorPosition (gST->ConOut, Column, Row); + return Print (L"%s", String); +} + +/** + Prints a chracter to the default console, at + the supplied cursor position, using L"%c" format. + + @param Column The cursor position to print the string at. + @param Row The cursor position to print the string at. + @param Character Character to print. + + @return Length of string printed to the console. + +**/ +UINTN +PrintCharAt ( + IN UINTN Column, + IN UINTN Row, + CHAR16 Character + ) +{ + gST->ConOut->SetCursorPosition (gST->ConOut, Column, Row); + return Print (L"%c", Character); +} + +/** + Count the storage space of a Unicode string which uses current lanaguag to get + from input string ID. + + @param StringId The input string to be counted. + + @return Storage space for the input string. + +**/ +UINTN +GetLineWidth ( + IN EFI_STRING_ID StringId + ) +{ + UINTN Index; + UINTN IncrementValue; + EFI_STRING String; + UINTN LineWidth; + + LineWidth = 0; + String = HiiGetString (gStringPackHandle, StringId, NULL); + + if (String != NULL) { + Index = 0; + IncrementValue = 1; + + do { + // + // Advance to the null-terminator or to the first width directive + // + for (; + (String[Index] != NARROW_CHAR) && (String[Index] != WIDE_CHAR) && (String[Index] != 0); + Index++, LineWidth = LineWidth + IncrementValue + ) + ; + + // + // We hit the null-terminator, we now have a count + // + if (String[Index] == 0) { + break; + } + // + // We encountered a narrow directive - strip it from the size calculation since it doesn't get printed + // and also set the flag that determines what we increment by.(if narrow, increment by 1, if wide increment by 2) + // + if (String[Index] == NARROW_CHAR) { + // + // Skip to the next character + // + Index++; + IncrementValue = 1; + } else { + // + // Skip to the next character + // + Index++; + IncrementValue = 2; + } + } while (String[Index] != 0); + FreePool (String); + } + + return LineWidth; +} + +/** + This function uses calculate the boot menu location, size and scroll bar information. + + @param BootMenuData The boot menu data to be proccessed. + + @return EFI_SUCCESS calculate boot menu information successful. + @retval EFI_INVALID_PARAMETER Input parameter is invalid + +**/ +EFI_STATUS +InitializeBootMenuScreen ( + IN OUT BOOT_MENU_POPUP_DATA *BootMenuData + ) +{ + UINTN MaxStrWidth; + UINTN StrWidth; + UINTN Index; + UINTN Column; + UINTN Row; + UINTN MaxPrintRows; + UINTN UnSelectableItmes; + + if (BootMenuData == NULL) { + return EFI_INVALID_PARAMETER; + } + // + // Get maximum string width + // + MaxStrWidth = 0; + for (Index = 0; Index < TITLE_TOKEN_COUNT; Index++) { + StrWidth = GetLineWidth (BootMenuData->TitleToken[Index]); + MaxStrWidth = MaxStrWidth > StrWidth ? MaxStrWidth : StrWidth; + } + + for (Index = 0; Index < BootMenuData->ItemCount; Index++) { + StrWidth = GetLineWidth (BootMenuData->PtrTokens[Index]); + MaxStrWidth = MaxStrWidth > StrWidth ? MaxStrWidth : StrWidth; + } + + for (Index = 0; Index < HELP_TOKEN_COUNT; Index++) { + StrWidth = GetLineWidth (BootMenuData->HelpToken[Index]); + MaxStrWidth = MaxStrWidth > StrWidth ? MaxStrWidth : StrWidth; + } + // + // query current row and column to calculate boot menu location + // + gST->ConOut->QueryMode ( + gST->ConOut, + gST->ConOut->Mode->Mode, + &Column, + &Row + ); + + MaxPrintRows = Row - 6; + UnSelectableItmes = TITLE_TOKEN_COUNT + 2 + HELP_TOKEN_COUNT + 2; + BootMenuData->MenuScreen.Width = MaxStrWidth + 8; + if (BootMenuData->ItemCount + UnSelectableItmes > MaxPrintRows) { + BootMenuData->MenuScreen.Height = MaxPrintRows; + BootMenuData->ScrollBarControl.HasScrollBar = TRUE; + BootMenuData->ScrollBarControl.ItemCountPerScreen = MaxPrintRows - UnSelectableItmes; + BootMenuData->ScrollBarControl.FirstItem = 0; + BootMenuData->ScrollBarControl.LastItem = MaxPrintRows - UnSelectableItmes - 1; + } else { + BootMenuData->MenuScreen.Height = BootMenuData->ItemCount + UnSelectableItmes; + BootMenuData->ScrollBarControl.HasScrollBar = FALSE; + BootMenuData->ScrollBarControl.ItemCountPerScreen = BootMenuData->ItemCount; + BootMenuData->ScrollBarControl.FirstItem = 0; + BootMenuData->ScrollBarControl.LastItem = BootMenuData->ItemCount - 1; + } + BootMenuData->MenuScreen.StartCol = (Column - BootMenuData->MenuScreen.Width) / 2; + BootMenuData->MenuScreen.StartRow = (Row - BootMenuData->MenuScreen.Height) / 2; + + return EFI_SUCCESS; +} +/** + This funciton uses check boot option is wheher setup application or no + + @param BootOption Pointer to EFI_BOOT_MANAGER_LOAD_OPTION array. + + @retval TRUE This boot option is setup application. + @retval FALSE This boot options isn't setup application + +**/ +BOOLEAN +IsBootManagerMenu ( + IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOption + ) +{ + EFI_STATUS Status; + EFI_BOOT_MANAGER_LOAD_OPTION BootManagerMenu; + + Status = EfiBootManagerGetBootManagerMenu (&BootManagerMenu); + if (!EFI_ERROR (Status)) { + EfiBootManagerFreeLoadOption (&BootManagerMenu); + } + + return (BOOLEAN) (!EFI_ERROR (Status) && (BootOption->OptionNumber == BootManagerMenu.OptionNumber)); +} + + +/** + This funciton uses to initialize boot menu data + + @param BootOption Pointer to EFI_BOOT_MANAGER_LOAD_OPTION array. + @param BootOptionCount Number of boot option. + @param BootMenuData The Input BootMenuData to be initialized. + + @retval EFI_SUCCESS Initialize boot menu data successful. + @retval EFI_INVALID_PARAMETER Input parameter is invalid. + +**/ +EFI_STATUS +InitializeBootMenuData ( + IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOption, + IN UINTN BootOptionCount, + OUT BOOT_MENU_POPUP_DATA *BootMenuData + ) +{ + UINTN Index; + UINTN StrIndex; + + if (BootOption == NULL || BootMenuData == NULL) { + return EFI_INVALID_PARAMETER; + } + + BootMenuData->TitleToken[0] = STRING_TOKEN (STR_BOOT_POPUP_MENU_TITLE_STRING); + BootMenuData->PtrTokens = AllocateZeroPool (BootOptionCount * sizeof (EFI_STRING_ID)); + ASSERT (BootMenuData->PtrTokens != NULL); + + // + // Skip boot option which created by BootNext Variable + // + for (StrIndex = 0, Index = 0; Index < BootOptionCount; Index++) { + // + // Don't display the hidden/inactive boot option except setup application. + // + if ((((BootOption[Index].Attributes & LOAD_OPTION_HIDDEN) != 0) || ((BootOption[Index].Attributes & LOAD_OPTION_ACTIVE) == 0)) && + !IsBootManagerMenu (&BootOption[Index])) { + continue; + } + ASSERT (BootOption[Index].Description != NULL); + BootMenuData->PtrTokens[StrIndex++] = HiiSetString ( + gStringPackHandle, + 0, + BootOption[Index].Description, + NULL + ); + } + + BootMenuData->ItemCount = StrIndex; + BootMenuData->HelpToken[0] = STRING_TOKEN (STR_BOOT_POPUP_MENU_HELP1_STRING); + BootMenuData->HelpToken[1] = STRING_TOKEN (STR_BOOT_POPUP_MENU_HELP2_STRING); + BootMenuData->HelpToken[2] = STRING_TOKEN (STR_BOOT_POPUP_MENU_HELP3_STRING); + InitializeBootMenuScreen (BootMenuData); + BootMenuData->SelectItem = 0; + return EFI_SUCCESS; +} + +/** + This function uses input select item to highlight selected item + and set current selected item in BootMenuData + + @param WantSelectItem The user wants to select item. + @param BootMenuData The boot menu data to be proccessed + + @return EFI_SUCCESS Highlight selected item and update current selected + item successful + @retval EFI_INVALID_PARAMETER Input parameter is invalid +**/ +EFI_STATUS +BootMenuSelectItem ( + IN UINTN WantSelectItem, + IN OUT BOOT_MENU_POPUP_DATA *BootMenuData + ) +{ + INT32 SavedAttribute; + EFI_STRING String; + UINTN StartCol; + UINTN StartRow; + UINTN PrintCol; + UINTN PrintRow; + UINTN TopShadeNum; + UINTN LowShadeNum; + UINTN FirstItem; + UINTN LastItem; + UINTN ItemCountPerScreen; + UINTN Index; + BOOLEAN RePaintItems; + + if (BootMenuData == NULL || WantSelectItem >= BootMenuData->ItemCount) { + return EFI_INVALID_PARAMETER; + } + SavedAttribute = gST->ConOut->Mode->Attribute; + RePaintItems = FALSE; + StartCol = BootMenuData->MenuScreen.StartCol; + StartRow = BootMenuData->MenuScreen.StartRow; + // + // print selectable items again and adjust scroll bar if need + // + if (BootMenuData->ScrollBarControl.HasScrollBar && + (WantSelectItem < BootMenuData->ScrollBarControl.FirstItem || + WantSelectItem > BootMenuData->ScrollBarControl.LastItem || + WantSelectItem == BootMenuData->SelectItem)) { + ItemCountPerScreen = BootMenuData->ScrollBarControl.ItemCountPerScreen; + // + // Set first item and last item + // + if (WantSelectItem < BootMenuData->ScrollBarControl.FirstItem) { + BootMenuData->ScrollBarControl.FirstItem = WantSelectItem; + BootMenuData->ScrollBarControl.LastItem = WantSelectItem + ItemCountPerScreen - 1; + } else if (WantSelectItem > BootMenuData->ScrollBarControl.LastItem) { + BootMenuData->ScrollBarControl.FirstItem = WantSelectItem - ItemCountPerScreen + 1; + BootMenuData->ScrollBarControl.LastItem = WantSelectItem; + } + gST->ConOut->SetAttribute (gST->ConOut, EFI_WHITE | EFI_BACKGROUND_BLUE); + FirstItem = BootMenuData->ScrollBarControl.FirstItem; + LastItem = BootMenuData->ScrollBarControl.LastItem; + TopShadeNum = 0; + if (FirstItem != 0) { + TopShadeNum = (FirstItem * ItemCountPerScreen) / BootMenuData->ItemCount; + if ((FirstItem * ItemCountPerScreen) % BootMenuData->ItemCount != 0) { + TopShadeNum++; + } + PrintCol = StartCol + BootMenuData->MenuScreen.Width - 2; + PrintRow = StartRow + TITLE_TOKEN_COUNT + 2; + for (Index = 0; Index < TopShadeNum; Index++, PrintRow++) { + PrintCharAt (PrintCol, PrintRow, BLOCKELEMENT_LIGHT_SHADE); + } + } + LowShadeNum = 0; + if (LastItem != BootMenuData->ItemCount - 1) { + LowShadeNum = ((BootMenuData->ItemCount - 1 - LastItem) * ItemCountPerScreen) / BootMenuData->ItemCount; + if (((BootMenuData->ItemCount - 1 - LastItem) * ItemCountPerScreen) % BootMenuData->ItemCount != 0) { + LowShadeNum++; + } + PrintCol = StartCol + BootMenuData->MenuScreen.Width - 2; + PrintRow = StartRow + TITLE_TOKEN_COUNT + 2 + ItemCountPerScreen - LowShadeNum; + for (Index = 0; Index < LowShadeNum; Index++, PrintRow++) { + PrintCharAt (PrintCol, PrintRow, BLOCKELEMENT_LIGHT_SHADE); + } + } + PrintCol = StartCol + BootMenuData->MenuScreen.Width - 2; + PrintRow = StartRow + TITLE_TOKEN_COUNT + 2 + TopShadeNum; + for (Index = TopShadeNum; Index < ItemCountPerScreen - LowShadeNum; Index++, PrintRow++) { + PrintCharAt (PrintCol, PrintRow, BLOCKELEMENT_FULL_BLOCK); + } + + + // + // Clear selectable items first + // + PrintCol = StartCol + 1; + PrintRow = StartRow + TITLE_TOKEN_COUNT + 2; + String = AllocateZeroPool ((BootMenuData->MenuScreen.Width - 2) * sizeof (CHAR16)); + ASSERT (String != NULL); + for (Index = 0; Index < BootMenuData->MenuScreen.Width - 3; Index++) { + String[Index] = 0x20; + } + for (Index = 0; Index < ItemCountPerScreen; Index++) { + PrintStringAt (PrintCol, PrintRow + Index, String); + } + FreePool (String); + // + // print selectable items + // + for (Index = 0; Index < ItemCountPerScreen; Index++, PrintRow++) { + String = HiiGetString (gStringPackHandle, BootMenuData->PtrTokens[Index + FirstItem], NULL); + PrintStringAt (PrintCol, PrintRow, String); + FreePool (String); + } + RePaintItems = TRUE; + } + + // + // Print want to select item + // + FirstItem = BootMenuData->ScrollBarControl.FirstItem; + gST->ConOut->SetAttribute (gST->ConOut, EFI_WHITE | EFI_BACKGROUND_BLACK); + String = HiiGetString (gStringPackHandle, BootMenuData->PtrTokens[WantSelectItem], NULL); + PrintCol = StartCol + 1; + PrintRow = StartRow + TITLE_TOKEN_COUNT + 2 + WantSelectItem - FirstItem; + PrintStringAt (PrintCol, PrintRow, String); + FreePool (String); + + // + // if Want Select and selected item isn't the same and doesn't re-draw selectable + // items, clear select item + // + if (WantSelectItem != BootMenuData->SelectItem && !RePaintItems) { + gST->ConOut->SetAttribute (gST->ConOut, EFI_WHITE | EFI_BACKGROUND_BLUE); + String = HiiGetString (gStringPackHandle, BootMenuData->PtrTokens[BootMenuData->SelectItem], NULL); + PrintCol = StartCol + 1; + PrintRow = StartRow + 3 + BootMenuData->SelectItem - FirstItem; + PrintStringAt (PrintCol, PrintRow, String); + FreePool (String); + } + + gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute); + BootMenuData->SelectItem = WantSelectItem; + return EFI_SUCCESS; +} + +/** + This funciton uses to draw boot popup menu + + @param BootMenuData The Input BootMenuData to be processed. + + @retval EFI_SUCCESS Draw boot popup menu successful. + +**/ +EFI_STATUS +DrawBootPopupMenu ( + IN BOOT_MENU_POPUP_DATA *BootMenuData + ) +{ + EFI_STRING String; + UINTN Index; + UINTN Width; + UINTN Height; + UINTN StartCol; + UINTN StartRow; + UINTN PrintRow; + UINTN PrintCol; + UINTN LineWidth; + INT32 SavedAttribute; + UINTN ItemCountPerScreen; + + gST->ConOut->ClearScreen (gST->ConOut); + + SavedAttribute = gST->ConOut->Mode->Attribute; + gST->ConOut->SetAttribute (gST->ConOut, EFI_WHITE | EFI_BACKGROUND_BLUE); + Width = BootMenuData->MenuScreen.Width; + Height = BootMenuData->MenuScreen.Height; + StartCol = BootMenuData->MenuScreen.StartCol; + StartRow = BootMenuData->MenuScreen.StartRow; + ItemCountPerScreen = BootMenuData->ScrollBarControl.ItemCountPerScreen; + PrintRow = StartRow; + + gST->ConOut->EnableCursor (gST->ConOut, FALSE); + // + // Draw Boot popup menu screen + // + PrintCharAt (StartCol, PrintRow, BOXDRAW_DOWN_RIGHT); + for (Index = 1; Index < Width - 1; Index++) { + PrintCharAt (StartCol + Index, PrintRow, BOXDRAW_HORIZONTAL); + } + PrintCharAt (StartCol + Width - 1, PrintRow, BOXDRAW_DOWN_LEFT); + + // + // Draw the screen for title + // + String = AllocateZeroPool ((Width - 1) * sizeof (CHAR16)); + ASSERT (String != NULL); + for (Index = 0; Index < Width - 2; Index++) { + String[Index] = 0x20; + } + + for (Index = 0; Index < TITLE_TOKEN_COUNT; Index++) { + PrintRow++; + PrintCharAt (StartCol, PrintRow, BOXDRAW_VERTICAL); + PrintStringAt (StartCol + 1, PrintRow, String); + PrintCharAt (StartCol + Width - 1, PrintRow, BOXDRAW_VERTICAL); + } + + PrintRow++; + PrintCharAt (StartCol, PrintRow, BOXDRAW_VERTICAL_RIGHT); + for (Index = 1; Index < Width - 1; Index++) { + PrintCharAt (StartCol + Index, PrintRow, BOXDRAW_HORIZONTAL); + } + PrintCharAt (StartCol + Width - 1, PrintRow, BOXDRAW_VERTICAL_LEFT); + + // + // Draw screen for selectable items + // + for (Index = 0; Index < ItemCountPerScreen; Index++) { + PrintRow++; + PrintCharAt (StartCol, PrintRow, BOXDRAW_VERTICAL); + PrintStringAt (StartCol + 1, PrintRow, String); + PrintCharAt (StartCol + Width - 1, PrintRow, BOXDRAW_VERTICAL); + } + + PrintRow++; + PrintCharAt (StartCol, PrintRow, BOXDRAW_VERTICAL_RIGHT); + for (Index = 1; Index < Width - 1; Index++) { + PrintCharAt (StartCol + Index, PrintRow, BOXDRAW_HORIZONTAL); + } + PrintCharAt (StartCol + Width - 1, PrintRow, BOXDRAW_VERTICAL_LEFT); + + // + // Draw screen for Help + // + for (Index = 0; Index < HELP_TOKEN_COUNT; Index++) { + PrintRow++; + PrintCharAt (StartCol, PrintRow, BOXDRAW_VERTICAL); + PrintStringAt (StartCol + 1, PrintRow, String); + PrintCharAt (StartCol + Width - 1, PrintRow, BOXDRAW_VERTICAL); + } + FreePool (String); + + PrintRow++; + PrintCharAt (StartCol, PrintRow, BOXDRAW_UP_RIGHT); + for (Index = 1; Index < Width - 1; Index++) { + PrintCharAt (StartCol + Index, PrintRow, BOXDRAW_HORIZONTAL); + } + PrintCharAt (StartCol + Width - 1, PrintRow, BOXDRAW_UP_LEFT); + + + // + // print title strings + // + PrintRow = StartRow + 1; + for (Index = 0; Index < TITLE_TOKEN_COUNT; Index++, PrintRow++) { + String = HiiGetString (gStringPackHandle, BootMenuData->TitleToken[Index], NULL); + LineWidth = GetLineWidth (BootMenuData->TitleToken[Index]); + PrintCol = StartCol + (Width - LineWidth) / 2; + PrintStringAt (PrintCol, PrintRow, String); + FreePool (String); + } + + // + // print selectable items + // + PrintCol = StartCol + 1; + PrintRow = StartRow + TITLE_TOKEN_COUNT + 2; + for (Index = 0; Index < ItemCountPerScreen; Index++, PrintRow++) { + String = HiiGetString (gStringPackHandle, BootMenuData->PtrTokens[Index], NULL); + PrintStringAt (PrintCol, PrintRow, String); + FreePool (String); + } + + // + // Print Help strings + // + PrintRow++; + for (Index = 0; Index < HELP_TOKEN_COUNT; Index++, PrintRow++) { + String = HiiGetString (gStringPackHandle, BootMenuData->HelpToken[Index], NULL); + LineWidth = GetLineWidth (BootMenuData->HelpToken[Index]); + PrintCol = StartCol + (Width - LineWidth) / 2; + PrintStringAt (PrintCol, PrintRow, String); + FreePool (String); + } + + // + // Print scroll bar if has scroll bar + // + if (BootMenuData->ScrollBarControl.HasScrollBar) { + PrintCol = StartCol + Width - 2; + PrintRow = StartRow + 2; + PrintCharAt (PrintCol, PrintRow, GEOMETRICSHAPE_UP_TRIANGLE); + PrintCharAt (PrintCol + 1, PrintRow, BOXDRAW_VERTICAL); + PrintRow += (ItemCountPerScreen + 1); + PrintCharAt (PrintCol, PrintRow, GEOMETRICSHAPE_DOWN_TRIANGLE); + PrintCharAt (PrintCol + 1, PrintRow, BOXDRAW_VERTICAL); + } + + gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute); + // + // Print Selected item + // + BootMenuSelectItem (BootMenuData->SelectItem, BootMenuData); + return EFI_SUCCESS; +} + +/** + This funciton uses to boot from selected item + + @param BootOptions Pointer to EFI_BOOT_MANAGER_LOAD_OPTION array. + @param BootOptionCount Number of boot option. + @param SelectItem Current selected item. +**/ +VOID +BootFromSelectOption ( + IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions, + IN UINTN BootOptionCount, + IN UINTN SelectItem + ) +{ + UINTN ItemNum; + UINTN Index; + + ASSERT (BootOptions != NULL); + + for (ItemNum = 0, Index = 0; Index < BootOptionCount; Index++) { + // + // Don't display the hidden/inactive boot option except setup application. + // + if ((((BootOptions[Index].Attributes & LOAD_OPTION_HIDDEN) != 0) || ((BootOptions[Index].Attributes & LOAD_OPTION_ACTIVE) == 0)) && + !IsBootManagerMenu (&BootOptions[Index])) { + continue; + } + if (ItemNum++ == SelectItem) { + EfiBootManagerBoot (&BootOptions[Index]); + break; + } + } +} + +/** + This function will change video resolution and text mode + according to defined setup mode or defined boot mode + + @param IsSetupMode Indicate mode is changed to setup mode or boot mode. + + @retval EFI_SUCCESS Mode is changed successfully. + @retval Others Mode failed to be changed. + +**/ +EFI_STATUS +EFIAPI +BdsSetConsoleMode ( + BOOLEAN IsSetupMode + ) +{ + EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput; + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOut; + UINTN SizeOfInfo; + EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info; + UINT32 MaxGopMode; + UINT32 MaxTextMode; + UINT32 ModeNumber; + UINT32 NewHorizontalResolution; + UINT32 NewVerticalResolution; + UINT32 NewColumns; + UINT32 NewRows; + UINTN HandleCount; + EFI_HANDLE *HandleBuffer; + EFI_STATUS Status; + UINTN Index; + UINTN CurrentColumn; + UINTN CurrentRow; + + MaxGopMode = 0; + MaxTextMode = 0; + + // + // Get current video resolution and text mode + // + Status = gBS->HandleProtocol ( + gST->ConsoleOutHandle, + &gEfiGraphicsOutputProtocolGuid, + (VOID**)&GraphicsOutput + ); + if (EFI_ERROR (Status)) { + GraphicsOutput = NULL; + } + + Status = gBS->HandleProtocol ( + gST->ConsoleOutHandle, + &gEfiSimpleTextOutProtocolGuid, + (VOID**)&SimpleTextOut + ); + if (EFI_ERROR (Status)) { + SimpleTextOut = NULL; + } + + if ((GraphicsOutput == NULL) || (SimpleTextOut == NULL)) { + return EFI_UNSUPPORTED; + } + + if (IsSetupMode) { + // + // The requried resolution and text mode is setup mode. + // + NewHorizontalResolution = mSetupHorizontalResolution; + NewVerticalResolution = mSetupVerticalResolution; + NewColumns = mSetupTextModeColumn; + NewRows = mSetupTextModeRow; + } else { + // + // The required resolution and text mode is boot mode. + // + NewHorizontalResolution = mBootHorizontalResolution; + NewVerticalResolution = mBootVerticalResolution; + NewColumns = mBootTextModeColumn; + NewRows = mBootTextModeRow; + } + + if (GraphicsOutput != NULL) { + MaxGopMode = GraphicsOutput->Mode->MaxMode; + } + + if (SimpleTextOut != NULL) { + MaxTextMode = SimpleTextOut->Mode->MaxMode; + } + + // + // 1. If current video resolution is same with required video resolution, + // video resolution need not be changed. + // 1.1. If current text mode is same with required text mode, text mode need not be changed. + // 1.2. If current text mode is different from required text mode, text mode need be changed. + // 2. If current video resolution is different from required video resolution, we need restart whole console drivers. + // + for (ModeNumber = 0; ModeNumber < MaxGopMode; ModeNumber++) { + Status = GraphicsOutput->QueryMode ( + GraphicsOutput, + ModeNumber, + &SizeOfInfo, + &Info + ); + if (!EFI_ERROR (Status)) { + if ((Info->HorizontalResolution == NewHorizontalResolution) && + (Info->VerticalResolution == NewVerticalResolution)) { + if ((GraphicsOutput->Mode->Info->HorizontalResolution == NewHorizontalResolution) && + (GraphicsOutput->Mode->Info->VerticalResolution == NewVerticalResolution)) { + // + // Current resolution is same with required resolution, check if text mode need be set + // + Status = SimpleTextOut->QueryMode (SimpleTextOut, SimpleTextOut->Mode->Mode, &CurrentColumn, &CurrentRow); + ASSERT_EFI_ERROR (Status); + if (CurrentColumn == NewColumns && CurrentRow == NewRows) { + // + // If current text mode is same with required text mode. Do nothing + // + FreePool (Info); + return EFI_SUCCESS; + } else { + // + // If current text mode is different from requried text mode. Set new video mode + // + for (Index = 0; Index < MaxTextMode; Index++) { + Status = SimpleTextOut->QueryMode (SimpleTextOut, Index, &CurrentColumn, &CurrentRow); + if (!EFI_ERROR(Status)) { + if ((CurrentColumn == NewColumns) && (CurrentRow == NewRows)) { + // + // Required text mode is supported, set it. + // + Status = SimpleTextOut->SetMode (SimpleTextOut, Index); + ASSERT_EFI_ERROR (Status); + // + // Update text mode PCD. + // + PcdSet32 (PcdConOutColumn, mSetupTextModeColumn); + PcdSet32 (PcdConOutRow, mSetupTextModeRow); + FreePool (Info); + return EFI_SUCCESS; + } + } + } + if (Index == MaxTextMode) { + // + // If requried text mode is not supported, return error. + // + FreePool (Info); + return EFI_UNSUPPORTED; + } + } + } else { + // + // If current video resolution is not same with the new one, set new video resolution. + // In this case, the driver which produces simple text out need be restarted. + // + Status = GraphicsOutput->SetMode (GraphicsOutput, ModeNumber); + if (!EFI_ERROR (Status)) { + FreePool (Info); + break; + } + } + } + FreePool (Info); + } + } + + if (ModeNumber == MaxGopMode) { + // + // If the resolution is not supported, return error. + // + return EFI_UNSUPPORTED; + } + + // + // Set PCD to Inform GraphicsConsole to change video resolution. + // Set PCD to Inform Consplitter to change text mode. + // + PcdSet32 (PcdVideoHorizontalResolution, NewHorizontalResolution); + PcdSet32 (PcdVideoVerticalResolution, NewVerticalResolution); + PcdSet32 (PcdConOutColumn, NewColumns); + PcdSet32 (PcdConOutRow, NewRows); + + + // + // Video mode is changed, so restart graphics console driver and higher level driver. + // Reconnect graphics console driver and higher level driver. + // Locate all the handles with GOP protocol and reconnect it. + // + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiSimpleTextOutProtocolGuid, + NULL, + &HandleCount, + &HandleBuffer + ); + if (!EFI_ERROR (Status)) { + for (Index = 0; Index < HandleCount; Index++) { + gBS->DisconnectController (HandleBuffer[Index], NULL, NULL); + } + for (Index = 0; Index < HandleCount; Index++) { + gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE); + } + if (HandleBuffer != NULL) { + FreePool (HandleBuffer); + } + } + + return EFI_SUCCESS; +} + +/** + Display the boot popup menu and allow user select boot item. + + @param ImageHandle The image handle. + @param SystemTable The system table. + + @retval EFI_SUCCESS Boot from selected boot option, and return success from boot option + @retval EFI_NOT_FOUND User select to enter setup or can not find boot option + +**/ +EFI_STATUS +EFIAPI +BootManagerMenuEntry ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_BOOT_MANAGER_LOAD_OPTION *BootOption; + UINTN BootOptionCount; + EFI_STATUS Status; + BOOT_MENU_POPUP_DATA BootMenuData; + UINTN Index; + EFI_INPUT_KEY Key; + BOOLEAN ExitApplication; + UINTN SelectItem; + EFI_BOOT_LOGO_PROTOCOL *BootLogo; + EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput; + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOut; + UINTN BootTextColumn; + UINTN BootTextRow; + + // + // Set Logo status invalid when boot manager menu is launched + // + BootLogo = NULL; + Status = gBS->LocateProtocol (&gEfiBootLogoProtocolGuid, NULL, (VOID **) &BootLogo); + if (!EFI_ERROR (Status) && (BootLogo != NULL)) { + Status = BootLogo->SetBootLogo (BootLogo, NULL, 0, 0, 0, 0); + ASSERT_EFI_ERROR (Status); + } + + gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL); + + gStringPackHandle = HiiAddPackages ( + &gEfiCallerIdGuid, + gImageHandle, + BootManagerMenuAppStrings, + NULL + ); + ASSERT (gStringPackHandle != NULL); + + // + // Connect all prior to entering the platform setup menu. + // + EfiBootManagerConnectAll (); + EfiBootManagerRefreshAllBootOption (); + + BootOption = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot); + + if (!mModeInitialized) { + // + // After the console is ready, get current video resolution + // and text mode before launching setup at first time. + // + Status = gBS->HandleProtocol ( + gST->ConsoleOutHandle, + &gEfiGraphicsOutputProtocolGuid, + (VOID**)&GraphicsOutput + ); + if (EFI_ERROR (Status)) { + GraphicsOutput = NULL; + } + + Status = gBS->HandleProtocol ( + gST->ConsoleOutHandle, + &gEfiSimpleTextOutProtocolGuid, + (VOID**)&SimpleTextOut + ); + if (EFI_ERROR (Status)) { + SimpleTextOut = NULL; + } + + if (GraphicsOutput != NULL) { + // + // Get current video resolution and text mode. + // + mBootHorizontalResolution = GraphicsOutput->Mode->Info->HorizontalResolution; + mBootVerticalResolution = GraphicsOutput->Mode->Info->VerticalResolution; + } + + if (SimpleTextOut != NULL) { + Status = SimpleTextOut->QueryMode ( + SimpleTextOut, + SimpleTextOut->Mode->Mode, + &BootTextColumn, + &BootTextRow + ); + mBootTextModeColumn = (UINT32)BootTextColumn; + mBootTextModeRow = (UINT32)BootTextRow; + } + + // + // Get user defined text mode for setup. + // + mSetupHorizontalResolution = PcdGet32 (PcdSetupVideoHorizontalResolution); + mSetupVerticalResolution = PcdGet32 (PcdSetupVideoVerticalResolution); + mSetupTextModeColumn = PcdGet32 (PcdSetupConOutColumn); + mSetupTextModeRow = PcdGet32 (PcdSetupConOutRow); + mModeInitialized = TRUE; + } + + // + // Set back to conventional setup resolution + // + BdsSetConsoleMode (TRUE); + + // + // Initialize Boot menu data + // + Status = InitializeBootMenuData (BootOption, BootOptionCount, &BootMenuData); + // + // According to boot menu data to draw boot popup menu + // + DrawBootPopupMenu (&BootMenuData); + + // + // check user input to determine want to re-draw or boot from user selected item + // + ExitApplication = FALSE; + while (!ExitApplication) { + gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &Index); + Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); + if (!EFI_ERROR (Status)) { + switch (Key.UnicodeChar) { + + case CHAR_NULL: + switch (Key.ScanCode) { + + case SCAN_UP: + SelectItem = BootMenuData.SelectItem == 0 ? BootMenuData.ItemCount - 1 : BootMenuData.SelectItem - 1; + BootMenuSelectItem (SelectItem, &BootMenuData); + break; + + case SCAN_DOWN: + SelectItem = BootMenuData.SelectItem == BootMenuData.ItemCount - 1 ? 0 : BootMenuData.SelectItem + 1; + BootMenuSelectItem (SelectItem, &BootMenuData); + break; + + case SCAN_ESC: + gST->ConOut->ClearScreen (gST->ConOut); + ExitApplication = TRUE; + // + // Set boot resolution for normal boot + // + BdsSetConsoleMode (FALSE); + break; + + default: + break; + } + break; + + case CHAR_CARRIAGE_RETURN: + gST->ConOut->ClearScreen (gST->ConOut); + // + // Set boot resolution for normal boot + // + BdsSetConsoleMode (FALSE); + BootFromSelectOption (BootOption, BootOptionCount, BootMenuData.SelectItem); + // + // Back to boot manager menu again, set back to setup resolution + // + BdsSetConsoleMode (TRUE); + DrawBootPopupMenu (&BootMenuData); + break; + + default: + break; + } + } + } + EfiBootManagerFreeLoadOptions (BootOption, BootOptionCount); + FreePool (BootMenuData.PtrTokens); + + HiiRemovePackages (gStringPackHandle); + + return Status; + +} diff --git a/MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenu.h b/MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenu.h new file mode 100644 index 0000000000..26d9a31865 --- /dev/null +++ b/MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenu.h @@ -0,0 +1,60 @@ +/** @file + FrontPage routines to handle the callbacks and browser calls + +Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + + +#ifndef _BOOT_MANAGER_MENU_H_ +#define _BOOT_MANAGER_MENU_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TITLE_TOKEN_COUNT 1 +#define HELP_TOKEN_COUNT 3 + +typedef struct _BOOT_MENU_SCREEN { + UINTN StartCol; + UINTN StartRow; + UINTN Width; + UINTN Height; +} BOOT_MENU_SCREEN; + +typedef struct _BOOT_MENU_SCROLL_BAR_CONTROL { + BOOLEAN HasScrollBar; + UINTN ItemCountPerScreen; + UINTN FirstItem; + UINTN LastItem; +} BOOT_MENU_SCROLL_BAR_CONTROL; + +typedef struct _BOOT_MENU_POPUP_DATA { + EFI_STRING_ID TitleToken[TITLE_TOKEN_COUNT]; // Title string ID + UINTN ItemCount; // Selectable item count + EFI_STRING_ID *PtrTokens; // All of selectable items string ID + EFI_STRING_ID HelpToken[HELP_TOKEN_COUNT]; // All of help string ID + UINTN SelectItem; // Current select item + BOOT_MENU_SCREEN MenuScreen; // Boot menu screen information + BOOT_MENU_SCROLL_BAR_CONTROL ScrollBarControl; // Boot menu scroll bar inoformation +} BOOT_MENU_POPUP_DATA; + +#endif + diff --git a/MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenuApp.inf b/MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenuApp.inf new file mode 100644 index 0000000000..c92a156a6a --- /dev/null +++ b/MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenuApp.inf @@ -0,0 +1,60 @@ +## @file +# The application to show the Boot Manager Menu. +# +# Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = BootManagerMenuApp + FILE_GUID = EEC25BDC-67F2-4D95-B1D5-F81B2039D11D + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + ENTRY_POINT = BootManagerMenuEntry + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + BootManagerMenu.c + BootManagerMenu.h + BootManagerMenuStrings.uni + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + HiiLib + DebugLib + UefiLib + MemoryAllocationLib + UefiBootServicesTableLib + UefiApplicationEntryPoint + UefiBootManagerLib + +[Guids] + +[Protocols] + gEfiBootLogoProtocolGuid ## CONSUMES + +[Pcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdConOutRow ## PRODUCES + gEfiMdeModulePkgTokenSpaceGuid.PcdConOutColumn ## PRODUCES + gEfiMdeModulePkgTokenSpaceGuid.PcdVideoHorizontalResolution ## PRODUCES + gEfiMdeModulePkgTokenSpaceGuid.PcdVideoVerticalResolution ## PRODUCES + gEfiMdeModulePkgTokenSpaceGuid.PcdSetupConOutColumn ## SOMETIMES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdSetupConOutRow ## SOMETIMES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdSetupVideoHorizontalResolution ## SOMETIMES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdSetupVideoVerticalResolution ## SOMETIMES_CONSUMES \ No newline at end of file diff --git a/MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenuStrings.uni b/MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenuStrings.uni new file mode 100644 index 0000000000..04fdd30fa7 Binary files /dev/null and b/MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenuStrings.uni differ diff --git a/MdeModulePkg/MdeModulePkg.dsc b/MdeModulePkg/MdeModulePkg.dsc index 1573942a24..14418f90b2 100644 --- a/MdeModulePkg/MdeModulePkg.dsc +++ b/MdeModulePkg/MdeModulePkg.dsc @@ -274,6 +274,7 @@ MdeModulePkg/Library/PlatformBootManagerLibNull/PlatformBootManagerLibNull.inf MdeModulePkg/Universal/BdsDxe/BdsDxe.inf + MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenuApp.inf MdeModulePkg/Universal/CapsulePei/CapsulePei.inf MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxe.inf -- cgit v1.2.3