--- /dev/null
+/** @file\r
+ The application to show the Boot Manager Menu.\r
+\r
+Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "BootManagerMenu.h"\r
+\r
+EFI_HII_HANDLE gStringPackHandle;\r
+\r
+BOOLEAN mModeInitialized = FALSE;\r
+\r
+//\r
+// Boot video resolution and text mode.\r
+//\r
+UINT32 mBootHorizontalResolution = 0;\r
+UINT32 mBootVerticalResolution = 0;\r
+UINT32 mBootTextModeColumn = 0;\r
+UINT32 mBootTextModeRow = 0;\r
+//\r
+// BIOS setup video resolution and text mode.\r
+//\r
+UINT32 mSetupTextModeColumn = 0;\r
+UINT32 mSetupTextModeRow = 0;\r
+UINT32 mSetupHorizontalResolution = 0;\r
+UINT32 mSetupVerticalResolution = 0;\r
+\r
+/**\r
+ Prints a unicode string to the default console, at\r
+ the supplied cursor position, using L"%s" format.\r
+\r
+ @param Column The cursor position to print the string at.\r
+ @param Row The cursor position to print the string at\r
+ @param String String pointer.\r
+\r
+ @return Length of string printed to the console\r
+\r
+**/\r
+UINTN\r
+PrintStringAt (\r
+ IN UINTN Column,\r
+ IN UINTN Row,\r
+ IN CHAR16 *String\r
+ )\r
+{\r
+\r
+ gST->ConOut->SetCursorPosition (gST->ConOut, Column, Row);\r
+ return Print (L"%s", String);\r
+}\r
+\r
+/**\r
+ Prints a chracter to the default console, at\r
+ the supplied cursor position, using L"%c" format.\r
+\r
+ @param Column The cursor position to print the string at.\r
+ @param Row The cursor position to print the string at.\r
+ @param Character Character to print.\r
+\r
+ @return Length of string printed to the console.\r
+\r
+**/\r
+UINTN\r
+PrintCharAt (\r
+ IN UINTN Column,\r
+ IN UINTN Row,\r
+ CHAR16 Character\r
+ )\r
+{\r
+ gST->ConOut->SetCursorPosition (gST->ConOut, Column, Row);\r
+ return Print (L"%c", Character);\r
+}\r
+\r
+/**\r
+ Count the storage space of a Unicode string which uses current lanaguag to get \r
+ from input string ID.\r
+\r
+ @param StringId The input string to be counted.\r
+\r
+ @return Storage space for the input string.\r
+\r
+**/\r
+UINTN\r
+GetLineWidth (\r
+ IN EFI_STRING_ID StringId\r
+ )\r
+{ \r
+ UINTN Index;\r
+ UINTN IncrementValue;\r
+ EFI_STRING String;\r
+ UINTN LineWidth;\r
+ \r
+ LineWidth = 0;\r
+ String = HiiGetString (gStringPackHandle, StringId, NULL); \r
+ \r
+ if (String != NULL) {\r
+ Index = 0;\r
+ IncrementValue = 1;\r
+ \r
+ do {\r
+ //\r
+ // Advance to the null-terminator or to the first width directive\r
+ //\r
+ for (;\r
+ (String[Index] != NARROW_CHAR) && (String[Index] != WIDE_CHAR) && (String[Index] != 0);\r
+ Index++, LineWidth = LineWidth + IncrementValue\r
+ )\r
+ ;\r
+ \r
+ //\r
+ // We hit the null-terminator, we now have a count\r
+ //\r
+ if (String[Index] == 0) {\r
+ break;\r
+ }\r
+ //\r
+ // We encountered a narrow directive - strip it from the size calculation since it doesn't get printed\r
+ // and also set the flag that determines what we increment by.(if narrow, increment by 1, if wide increment by 2)\r
+ //\r
+ if (String[Index] == NARROW_CHAR) {\r
+ //\r
+ // Skip to the next character\r
+ //\r
+ Index++;\r
+ IncrementValue = 1;\r
+ } else {\r
+ //\r
+ // Skip to the next character\r
+ //\r
+ Index++;\r
+ IncrementValue = 2;\r
+ }\r
+ } while (String[Index] != 0); \r
+ FreePool (String);\r
+ }\r
+ \r
+ return LineWidth; \r
+}\r
+\r
+/**\r
+ This function uses calculate the boot menu location, size and scroll bar information.\r
+\r
+ @param BootMenuData The boot menu data to be proccessed.\r
+\r
+ @return EFI_SUCCESS calculate boot menu information successful.\r
+ @retval EFI_INVALID_PARAMETER Input parameter is invalid \r
+\r
+**/\r
+EFI_STATUS \r
+InitializeBootMenuScreen (\r
+ IN OUT BOOT_MENU_POPUP_DATA *BootMenuData\r
+ )\r
+{\r
+ UINTN MaxStrWidth;\r
+ UINTN StrWidth;\r
+ UINTN Index;\r
+ UINTN Column;\r
+ UINTN Row;\r
+ UINTN MaxPrintRows;\r
+ UINTN UnSelectableItmes;\r
+\r
+ if (BootMenuData == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ //\r
+ // Get maximum string width\r
+ //\r
+ MaxStrWidth = 0; \r
+ for (Index = 0; Index < TITLE_TOKEN_COUNT; Index++) { \r
+ StrWidth = GetLineWidth (BootMenuData->TitleToken[Index]);\r
+ MaxStrWidth = MaxStrWidth > StrWidth ? MaxStrWidth : StrWidth;\r
+ }\r
+ \r
+ for (Index = 0; Index < BootMenuData->ItemCount; Index++) {\r
+ StrWidth = GetLineWidth (BootMenuData->PtrTokens[Index]);\r
+ MaxStrWidth = MaxStrWidth > StrWidth ? MaxStrWidth : StrWidth; \r
+ } \r
+ \r
+ for (Index = 0; Index < HELP_TOKEN_COUNT; Index++) { \r
+ StrWidth = GetLineWidth (BootMenuData->HelpToken[Index]);\r
+ MaxStrWidth = MaxStrWidth > StrWidth ? MaxStrWidth : StrWidth;\r
+ } \r
+ //\r
+ // query current row and column to calculate boot menu location\r
+ //\r
+ gST->ConOut->QueryMode (\r
+ gST->ConOut,\r
+ gST->ConOut->Mode->Mode,\r
+ &Column,\r
+ &Row\r
+ ); \r
+ \r
+ MaxPrintRows = Row - 6; \r
+ UnSelectableItmes = TITLE_TOKEN_COUNT + 2 + HELP_TOKEN_COUNT + 2; \r
+ BootMenuData->MenuScreen.Width = MaxStrWidth + 8;\r
+ if (BootMenuData->ItemCount + UnSelectableItmes > MaxPrintRows) {\r
+ BootMenuData->MenuScreen.Height = MaxPrintRows;\r
+ BootMenuData->ScrollBarControl.HasScrollBar = TRUE;\r
+ BootMenuData->ScrollBarControl.ItemCountPerScreen = MaxPrintRows - UnSelectableItmes;\r
+ BootMenuData->ScrollBarControl.FirstItem = 0;\r
+ BootMenuData->ScrollBarControl.LastItem = MaxPrintRows - UnSelectableItmes - 1;\r
+ } else {\r
+ BootMenuData->MenuScreen.Height = BootMenuData->ItemCount + UnSelectableItmes;\r
+ BootMenuData->ScrollBarControl.HasScrollBar = FALSE;\r
+ BootMenuData->ScrollBarControl.ItemCountPerScreen = BootMenuData->ItemCount;\r
+ BootMenuData->ScrollBarControl.FirstItem = 0;\r
+ BootMenuData->ScrollBarControl.LastItem = BootMenuData->ItemCount - 1; \r
+ }\r
+ BootMenuData->MenuScreen.StartCol = (Column - BootMenuData->MenuScreen.Width) / 2; \r
+ BootMenuData->MenuScreen.StartRow = (Row - BootMenuData->MenuScreen.Height) / 2; \r
+\r
+ return EFI_SUCCESS;\r
+}\r
+/**\r
+ This funciton uses check boot option is wheher setup application or no\r
+\r
+ @param BootOption Pointer to EFI_BOOT_MANAGER_LOAD_OPTION array.\r
+ \r
+ @retval TRUE This boot option is setup application.\r
+ @retval FALSE This boot options isn't setup application\r
+\r
+**/\r
+BOOLEAN\r
+IsBootManagerMenu (\r
+ IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOption\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_BOOT_MANAGER_LOAD_OPTION BootManagerMenu;\r
+\r
+ Status = EfiBootManagerGetBootManagerMenu (&BootManagerMenu);\r
+ if (!EFI_ERROR (Status)) {\r
+ EfiBootManagerFreeLoadOption (&BootManagerMenu);\r
+ }\r
+\r
+ return (BOOLEAN) (!EFI_ERROR (Status) && (BootOption->OptionNumber == BootManagerMenu.OptionNumber));\r
+}\r
+ \r
+\r
+/**\r
+ This funciton uses to initialize boot menu data\r
+\r
+ @param BootOption Pointer to EFI_BOOT_MANAGER_LOAD_OPTION array.\r
+ @param BootOptionCount Number of boot option.\r
+ @param BootMenuData The Input BootMenuData to be initialized.\r
+ \r
+ @retval EFI_SUCCESS Initialize boot menu data successful.\r
+ @retval EFI_INVALID_PARAMETER Input parameter is invalid. \r
+\r
+**/\r
+EFI_STATUS\r
+InitializeBootMenuData (\r
+ IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOption,\r
+ IN UINTN BootOptionCount,\r
+ OUT BOOT_MENU_POPUP_DATA *BootMenuData\r
+ )\r
+{\r
+ UINTN Index;\r
+ UINTN StrIndex;\r
+ \r
+ if (BootOption == NULL || BootMenuData == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ } \r
+ \r
+ BootMenuData->TitleToken[0] = STRING_TOKEN (STR_BOOT_POPUP_MENU_TITLE_STRING);\r
+ BootMenuData->PtrTokens = AllocateZeroPool (BootOptionCount * sizeof (EFI_STRING_ID));\r
+ ASSERT (BootMenuData->PtrTokens != NULL);\r
+\r
+ //\r
+ // Skip boot option which created by BootNext Variable\r
+ //\r
+ for (StrIndex = 0, Index = 0; Index < BootOptionCount; Index++) {\r
+ //\r
+ // Don't display the hidden/inactive boot option except setup application.\r
+ //\r
+ if ((((BootOption[Index].Attributes & LOAD_OPTION_HIDDEN) != 0) || ((BootOption[Index].Attributes & LOAD_OPTION_ACTIVE) == 0)) &&\r
+ !IsBootManagerMenu (&BootOption[Index])) { \r
+ continue;\r
+ }\r
+ ASSERT (BootOption[Index].Description != NULL);\r
+ BootMenuData->PtrTokens[StrIndex++] = HiiSetString (\r
+ gStringPackHandle, \r
+ 0,\r
+ BootOption[Index].Description,\r
+ NULL\r
+ );\r
+ }\r
+\r
+ BootMenuData->ItemCount = StrIndex; \r
+ BootMenuData->HelpToken[0] = STRING_TOKEN (STR_BOOT_POPUP_MENU_HELP1_STRING);\r
+ BootMenuData->HelpToken[1] = STRING_TOKEN (STR_BOOT_POPUP_MENU_HELP2_STRING);\r
+ BootMenuData->HelpToken[2] = STRING_TOKEN (STR_BOOT_POPUP_MENU_HELP3_STRING);\r
+ InitializeBootMenuScreen (BootMenuData);\r
+ BootMenuData->SelectItem = 0;\r
+ return EFI_SUCCESS;\r
+} \r
+\r
+/**\r
+ This function uses input select item to highlight selected item\r
+ and set current selected item in BootMenuData\r
+\r
+ @param WantSelectItem The user wants to select item.\r
+ @param BootMenuData The boot menu data to be proccessed\r
+\r
+ @return EFI_SUCCESS Highlight selected item and update current selected \r
+ item successful \r
+ @retval EFI_INVALID_PARAMETER Input parameter is invalid \r
+**/\r
+EFI_STATUS\r
+BootMenuSelectItem (\r
+ IN UINTN WantSelectItem,\r
+ IN OUT BOOT_MENU_POPUP_DATA *BootMenuData\r
+ )\r
+{\r
+ INT32 SavedAttribute;\r
+ EFI_STRING String;\r
+ UINTN StartCol; \r
+ UINTN StartRow;\r
+ UINTN PrintCol;\r
+ UINTN PrintRow;\r
+ UINTN TopShadeNum;\r
+ UINTN LowShadeNum;\r
+ UINTN FirstItem;\r
+ UINTN LastItem;\r
+ UINTN ItemCountPerScreen;\r
+ UINTN Index;\r
+ BOOLEAN RePaintItems;\r
+ \r
+ if (BootMenuData == NULL || WantSelectItem >= BootMenuData->ItemCount) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ SavedAttribute = gST->ConOut->Mode->Attribute;\r
+ RePaintItems = FALSE;\r
+ StartCol = BootMenuData->MenuScreen.StartCol;\r
+ StartRow = BootMenuData->MenuScreen.StartRow;\r
+ //\r
+ // print selectable items again and adjust scroll bar if need\r
+ // \r
+ if (BootMenuData->ScrollBarControl.HasScrollBar &&\r
+ (WantSelectItem < BootMenuData->ScrollBarControl.FirstItem ||\r
+ WantSelectItem > BootMenuData->ScrollBarControl.LastItem ||\r
+ WantSelectItem == BootMenuData->SelectItem)) { \r
+ ItemCountPerScreen = BootMenuData->ScrollBarControl.ItemCountPerScreen;\r
+ //\r
+ // Set first item and last item\r
+ // \r
+ if (WantSelectItem < BootMenuData->ScrollBarControl.FirstItem) {\r
+ BootMenuData->ScrollBarControl.FirstItem = WantSelectItem;\r
+ BootMenuData->ScrollBarControl.LastItem = WantSelectItem + ItemCountPerScreen - 1; \r
+ } else if (WantSelectItem > BootMenuData->ScrollBarControl.LastItem) {\r
+ BootMenuData->ScrollBarControl.FirstItem = WantSelectItem - ItemCountPerScreen + 1; \r
+ BootMenuData->ScrollBarControl.LastItem = WantSelectItem;\r
+ }\r
+ gST->ConOut->SetAttribute (gST->ConOut, EFI_WHITE | EFI_BACKGROUND_BLUE);\r
+ FirstItem = BootMenuData->ScrollBarControl.FirstItem;\r
+ LastItem = BootMenuData->ScrollBarControl.LastItem;\r
+ TopShadeNum = 0;\r
+ if (FirstItem != 0) {\r
+ TopShadeNum = (FirstItem * ItemCountPerScreen) / BootMenuData->ItemCount;\r
+ if ((FirstItem * ItemCountPerScreen) % BootMenuData->ItemCount != 0) {\r
+ TopShadeNum++;\r
+ }\r
+ PrintCol = StartCol + BootMenuData->MenuScreen.Width - 2;\r
+ PrintRow = StartRow + TITLE_TOKEN_COUNT + 2; \r
+ for (Index = 0; Index < TopShadeNum; Index++, PrintRow++) {\r
+ PrintCharAt (PrintCol, PrintRow, BLOCKELEMENT_LIGHT_SHADE);\r
+ }\r
+ }\r
+ LowShadeNum = 0;\r
+ if (LastItem != BootMenuData->ItemCount - 1) {\r
+ LowShadeNum = ((BootMenuData->ItemCount - 1 - LastItem) * ItemCountPerScreen) / BootMenuData->ItemCount;\r
+ if (((BootMenuData->ItemCount - 1 - LastItem) * ItemCountPerScreen) % BootMenuData->ItemCount != 0) {\r
+ LowShadeNum++;\r
+ }\r
+ PrintCol = StartCol + BootMenuData->MenuScreen.Width - 2;\r
+ PrintRow = StartRow + TITLE_TOKEN_COUNT + 2 + ItemCountPerScreen - LowShadeNum; \r
+ for (Index = 0; Index < LowShadeNum; Index++, PrintRow++) {\r
+ PrintCharAt (PrintCol, PrintRow, BLOCKELEMENT_LIGHT_SHADE);\r
+ } \r
+ }\r
+ PrintCol = StartCol + BootMenuData->MenuScreen.Width - 2;\r
+ PrintRow = StartRow + TITLE_TOKEN_COUNT + 2 + TopShadeNum; \r
+ for (Index = TopShadeNum; Index < ItemCountPerScreen - LowShadeNum; Index++, PrintRow++) {\r
+ PrintCharAt (PrintCol, PrintRow, BLOCKELEMENT_FULL_BLOCK);\r
+ } \r
+\r
+\r
+ //\r
+ // Clear selectable items first\r
+ //\r
+ PrintCol = StartCol + 1;\r
+ PrintRow = StartRow + TITLE_TOKEN_COUNT + 2; \r
+ String = AllocateZeroPool ((BootMenuData->MenuScreen.Width - 2) * sizeof (CHAR16));\r
+ ASSERT (String != NULL);\r
+ for (Index = 0; Index < BootMenuData->MenuScreen.Width - 3; Index++) {\r
+ String[Index] = 0x20;\r
+ } \r
+ for (Index = 0; Index < ItemCountPerScreen; Index++) { \r
+ PrintStringAt (PrintCol, PrintRow + Index, String); \r
+ }\r
+ FreePool (String);\r
+ //\r
+ // print selectable items \r
+ //\r
+ for (Index = 0; Index < ItemCountPerScreen; Index++, PrintRow++) {\r
+ String = HiiGetString (gStringPackHandle, BootMenuData->PtrTokens[Index + FirstItem], NULL);\r
+ PrintStringAt (PrintCol, PrintRow, String);\r
+ FreePool (String); \r
+ }\r
+ RePaintItems = TRUE;\r
+ }\r
+ \r
+ //\r
+ // Print want to select item \r
+ //\r
+ FirstItem = BootMenuData->ScrollBarControl.FirstItem;\r
+ gST->ConOut->SetAttribute (gST->ConOut, EFI_WHITE | EFI_BACKGROUND_BLACK);\r
+ String = HiiGetString (gStringPackHandle, BootMenuData->PtrTokens[WantSelectItem], NULL);\r
+ PrintCol = StartCol + 1; \r
+ PrintRow = StartRow + TITLE_TOKEN_COUNT + 2 + WantSelectItem - FirstItem; \r
+ PrintStringAt (PrintCol, PrintRow, String);\r
+ FreePool (String);\r
+ \r
+ //\r
+ // if Want Select and selected item isn't the same and doesn't re-draw selectable \r
+ // items, clear select item\r
+ //\r
+ if (WantSelectItem != BootMenuData->SelectItem && !RePaintItems) {\r
+ gST->ConOut->SetAttribute (gST->ConOut, EFI_WHITE | EFI_BACKGROUND_BLUE);\r
+ String = HiiGetString (gStringPackHandle, BootMenuData->PtrTokens[BootMenuData->SelectItem], NULL);\r
+ PrintCol = StartCol + 1; \r
+ PrintRow = StartRow + 3 + BootMenuData->SelectItem - FirstItem; \r
+ PrintStringAt (PrintCol, PrintRow, String);\r
+ FreePool (String); \r
+ }\r
+\r
+ gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute);\r
+ BootMenuData->SelectItem = WantSelectItem;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ This funciton uses to draw boot popup menu\r
+\r
+ @param BootMenuData The Input BootMenuData to be processed.\r
+ \r
+ @retval EFI_SUCCESS Draw boot popup menu successful.\r
+\r
+**/\r
+EFI_STATUS \r
+DrawBootPopupMenu (\r
+ IN BOOT_MENU_POPUP_DATA *BootMenuData\r
+ )\r
+{\r
+ EFI_STRING String;\r
+ UINTN Index;\r
+ UINTN Width; \r
+ UINTN Height;\r
+ UINTN StartCol;\r
+ UINTN StartRow;\r
+ UINTN PrintRow;\r
+ UINTN PrintCol;\r
+ UINTN LineWidth;\r
+ INT32 SavedAttribute; \r
+ UINTN ItemCountPerScreen; \r
+\r
+ gST->ConOut->ClearScreen (gST->ConOut);\r
+ \r
+ SavedAttribute = gST->ConOut->Mode->Attribute;\r
+ gST->ConOut->SetAttribute (gST->ConOut, EFI_WHITE | EFI_BACKGROUND_BLUE);\r
+ Width = BootMenuData->MenuScreen.Width;\r
+ Height = BootMenuData->MenuScreen.Height;\r
+ StartCol = BootMenuData->MenuScreen.StartCol;\r
+ StartRow = BootMenuData->MenuScreen.StartRow;\r
+ ItemCountPerScreen = BootMenuData->ScrollBarControl.ItemCountPerScreen;\r
+ PrintRow = StartRow;\r
+ \r
+ gST->ConOut->EnableCursor (gST->ConOut, FALSE);\r
+ //\r
+ // Draw Boot popup menu screen\r
+ //\r
+ PrintCharAt (StartCol, PrintRow, BOXDRAW_DOWN_RIGHT);\r
+ for (Index = 1; Index < Width - 1; Index++) {\r
+ PrintCharAt (StartCol + Index, PrintRow, BOXDRAW_HORIZONTAL); \r
+ }\r
+ PrintCharAt (StartCol + Width - 1, PrintRow, BOXDRAW_DOWN_LEFT);\r
+ \r
+ //\r
+ // Draw the screen for title\r
+ //\r
+ String = AllocateZeroPool ((Width - 1) * sizeof (CHAR16));\r
+ ASSERT (String != NULL);\r
+ for (Index = 0; Index < Width - 2; Index++) {\r
+ String[Index] = 0x20;\r
+ }\r
+\r
+ for (Index = 0; Index < TITLE_TOKEN_COUNT; Index++) {\r
+ PrintRow++;\r
+ PrintCharAt (StartCol, PrintRow, BOXDRAW_VERTICAL); \r
+ PrintStringAt (StartCol + 1, PrintRow, String);\r
+ PrintCharAt (StartCol + Width - 1, PrintRow, BOXDRAW_VERTICAL);\r
+ }\r
+ \r
+ PrintRow++;\r
+ PrintCharAt (StartCol, PrintRow, BOXDRAW_VERTICAL_RIGHT);\r
+ for (Index = 1; Index < Width - 1; Index++) {\r
+ PrintCharAt (StartCol + Index, PrintRow, BOXDRAW_HORIZONTAL); \r
+ }\r
+ PrintCharAt (StartCol + Width - 1, PrintRow, BOXDRAW_VERTICAL_LEFT); \r
+ \r
+ //\r
+ // Draw screen for selectable items\r
+ //\r
+ for (Index = 0; Index < ItemCountPerScreen; Index++) {\r
+ PrintRow++;\r
+ PrintCharAt (StartCol, PrintRow, BOXDRAW_VERTICAL);\r
+ PrintStringAt (StartCol + 1, PrintRow, String);\r
+ PrintCharAt (StartCol + Width - 1, PrintRow, BOXDRAW_VERTICAL);\r
+ } \r
+\r
+ PrintRow++;\r
+ PrintCharAt (StartCol, PrintRow, BOXDRAW_VERTICAL_RIGHT);\r
+ for (Index = 1; Index < Width - 1; Index++) {\r
+ PrintCharAt (StartCol + Index, PrintRow, BOXDRAW_HORIZONTAL); \r
+ }\r
+ PrintCharAt (StartCol + Width - 1, PrintRow, BOXDRAW_VERTICAL_LEFT);\r
+ \r
+ //\r
+ // Draw screen for Help\r
+ //\r
+ for (Index = 0; Index < HELP_TOKEN_COUNT; Index++) {\r
+ PrintRow++;\r
+ PrintCharAt (StartCol, PrintRow, BOXDRAW_VERTICAL);\r
+ PrintStringAt (StartCol + 1, PrintRow, String);\r
+ PrintCharAt (StartCol + Width - 1, PrintRow, BOXDRAW_VERTICAL);\r
+ }\r
+ FreePool (String); \r
+ \r
+ PrintRow++; \r
+ PrintCharAt (StartCol, PrintRow, BOXDRAW_UP_RIGHT);\r
+ for (Index = 1; Index < Width - 1; Index++) {\r
+ PrintCharAt (StartCol + Index, PrintRow, BOXDRAW_HORIZONTAL); \r
+ }\r
+ PrintCharAt (StartCol + Width - 1, PrintRow, BOXDRAW_UP_LEFT); \r
+ \r
+ \r
+ //\r
+ // print title strings\r
+ //\r
+ PrintRow = StartRow + 1;\r
+ for (Index = 0; Index < TITLE_TOKEN_COUNT; Index++, PrintRow++) {\r
+ String = HiiGetString (gStringPackHandle, BootMenuData->TitleToken[Index], NULL);\r
+ LineWidth = GetLineWidth (BootMenuData->TitleToken[Index]); \r
+ PrintCol = StartCol + (Width - LineWidth) / 2;\r
+ PrintStringAt (PrintCol, PrintRow, String);\r
+ FreePool (String);\r
+ }\r
+ \r
+ //\r
+ // print selectable items\r
+ //\r
+ PrintCol = StartCol + 1;\r
+ PrintRow = StartRow + TITLE_TOKEN_COUNT + 2; \r
+ for (Index = 0; Index < ItemCountPerScreen; Index++, PrintRow++) {\r
+ String = HiiGetString (gStringPackHandle, BootMenuData->PtrTokens[Index], NULL);\r
+ PrintStringAt (PrintCol, PrintRow, String);\r
+ FreePool (String); \r
+ }\r
+ \r
+ //\r
+ // Print Help strings\r
+ //\r
+ PrintRow++;\r
+ for (Index = 0; Index < HELP_TOKEN_COUNT; Index++, PrintRow++) {\r
+ String = HiiGetString (gStringPackHandle, BootMenuData->HelpToken[Index], NULL);\r
+ LineWidth = GetLineWidth (BootMenuData->HelpToken[Index]);\r
+ PrintCol = StartCol + (Width - LineWidth) / 2;\r
+ PrintStringAt (PrintCol, PrintRow, String);\r
+ FreePool (String);\r
+ }\r
+ \r
+ //\r
+ // Print scroll bar if has scroll bar\r
+ //\r
+ if (BootMenuData->ScrollBarControl.HasScrollBar) {\r
+ PrintCol = StartCol + Width - 2;\r
+ PrintRow = StartRow + 2; \r
+ PrintCharAt (PrintCol, PrintRow, GEOMETRICSHAPE_UP_TRIANGLE); \r
+ PrintCharAt (PrintCol + 1, PrintRow, BOXDRAW_VERTICAL); \r
+ PrintRow += (ItemCountPerScreen + 1); \r
+ PrintCharAt (PrintCol, PrintRow, GEOMETRICSHAPE_DOWN_TRIANGLE);\r
+ PrintCharAt (PrintCol + 1, PrintRow, BOXDRAW_VERTICAL); \r
+ } \r
+ \r
+ gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute);\r
+ //\r
+ // Print Selected item\r
+ //\r
+ BootMenuSelectItem (BootMenuData->SelectItem, BootMenuData);\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ This funciton uses to boot from selected item \r
+\r
+ @param BootOptions Pointer to EFI_BOOT_MANAGER_LOAD_OPTION array.\r
+ @param BootOptionCount Number of boot option.\r
+ @param SelectItem Current selected item.\r
+**/\r
+VOID\r
+BootFromSelectOption (\r
+ IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions,\r
+ IN UINTN BootOptionCount, \r
+ IN UINTN SelectItem\r
+ )\r
+{\r
+ UINTN ItemNum;\r
+ UINTN Index;\r
+\r
+ ASSERT (BootOptions != NULL);\r
+\r
+ for (ItemNum = 0, Index = 0; Index < BootOptionCount; Index++) {\r
+ //\r
+ // Don't display the hidden/inactive boot option except setup application.\r
+ //\r
+ if ((((BootOptions[Index].Attributes & LOAD_OPTION_HIDDEN) != 0) || ((BootOptions[Index].Attributes & LOAD_OPTION_ACTIVE) == 0)) &&\r
+ !IsBootManagerMenu (&BootOptions[Index])) { \r
+ continue;\r
+ }\r
+ if (ItemNum++ == SelectItem) {\r
+ EfiBootManagerBoot (&BootOptions[Index]);\r
+ break;\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ This function will change video resolution and text mode\r
+ according to defined setup mode or defined boot mode \r
+\r
+ @param IsSetupMode Indicate mode is changed to setup mode or boot mode. \r
+\r
+ @retval EFI_SUCCESS Mode is changed successfully.\r
+ @retval Others Mode failed to be changed.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BdsSetConsoleMode (\r
+ BOOLEAN IsSetupMode\r
+ )\r
+{\r
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;\r
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOut;\r
+ UINTN SizeOfInfo;\r
+ EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;\r
+ UINT32 MaxGopMode;\r
+ UINT32 MaxTextMode;\r
+ UINT32 ModeNumber;\r
+ UINT32 NewHorizontalResolution;\r
+ UINT32 NewVerticalResolution;\r
+ UINT32 NewColumns;\r
+ UINT32 NewRows;\r
+ UINTN HandleCount;\r
+ EFI_HANDLE *HandleBuffer;\r
+ EFI_STATUS Status;\r
+ UINTN Index;\r
+ UINTN CurrentColumn;\r
+ UINTN CurrentRow; \r
+\r
+ MaxGopMode = 0;\r
+ MaxTextMode = 0;\r
+\r
+ //\r
+ // Get current video resolution and text mode \r
+ //\r
+ Status = gBS->HandleProtocol (\r
+ gST->ConsoleOutHandle,\r
+ &gEfiGraphicsOutputProtocolGuid,\r
+ (VOID**)&GraphicsOutput\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ GraphicsOutput = NULL;\r
+ }\r
+\r
+ Status = gBS->HandleProtocol (\r
+ gST->ConsoleOutHandle,\r
+ &gEfiSimpleTextOutProtocolGuid,\r
+ (VOID**)&SimpleTextOut\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ SimpleTextOut = NULL;\r
+ } \r
+\r
+ if ((GraphicsOutput == NULL) || (SimpleTextOut == NULL)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ if (IsSetupMode) {\r
+ //\r
+ // The requried resolution and text mode is setup mode.\r
+ //\r
+ NewHorizontalResolution = mSetupHorizontalResolution;\r
+ NewVerticalResolution = mSetupVerticalResolution;\r
+ NewColumns = mSetupTextModeColumn;\r
+ NewRows = mSetupTextModeRow;\r
+ } else {\r
+ //\r
+ // The required resolution and text mode is boot mode.\r
+ //\r
+ NewHorizontalResolution = mBootHorizontalResolution;\r
+ NewVerticalResolution = mBootVerticalResolution;\r
+ NewColumns = mBootTextModeColumn;\r
+ NewRows = mBootTextModeRow; \r
+ }\r
+ \r
+ if (GraphicsOutput != NULL) {\r
+ MaxGopMode = GraphicsOutput->Mode->MaxMode;\r
+ } \r
+\r
+ if (SimpleTextOut != NULL) {\r
+ MaxTextMode = SimpleTextOut->Mode->MaxMode;\r
+ }\r
+\r
+ //\r
+ // 1. If current video resolution is same with required video resolution,\r
+ // video resolution need not be changed.\r
+ // 1.1. If current text mode is same with required text mode, text mode need not be changed.\r
+ // 1.2. If current text mode is different from required text mode, text mode need be changed.\r
+ // 2. If current video resolution is different from required video resolution, we need restart whole console drivers.\r
+ //\r
+ for (ModeNumber = 0; ModeNumber < MaxGopMode; ModeNumber++) {\r
+ Status = GraphicsOutput->QueryMode (\r
+ GraphicsOutput,\r
+ ModeNumber,\r
+ &SizeOfInfo,\r
+ &Info\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ if ((Info->HorizontalResolution == NewHorizontalResolution) &&\r
+ (Info->VerticalResolution == NewVerticalResolution)) {\r
+ if ((GraphicsOutput->Mode->Info->HorizontalResolution == NewHorizontalResolution) &&\r
+ (GraphicsOutput->Mode->Info->VerticalResolution == NewVerticalResolution)) {\r
+ //\r
+ // Current resolution is same with required resolution, check if text mode need be set\r
+ //\r
+ Status = SimpleTextOut->QueryMode (SimpleTextOut, SimpleTextOut->Mode->Mode, &CurrentColumn, &CurrentRow);\r
+ ASSERT_EFI_ERROR (Status);\r
+ if (CurrentColumn == NewColumns && CurrentRow == NewRows) {\r
+ //\r
+ // If current text mode is same with required text mode. Do nothing\r
+ //\r
+ FreePool (Info);\r
+ return EFI_SUCCESS;\r
+ } else {\r
+ //\r
+ // If current text mode is different from requried text mode. Set new video mode\r
+ //\r
+ for (Index = 0; Index < MaxTextMode; Index++) {\r
+ Status = SimpleTextOut->QueryMode (SimpleTextOut, Index, &CurrentColumn, &CurrentRow);\r
+ if (!EFI_ERROR(Status)) {\r
+ if ((CurrentColumn == NewColumns) && (CurrentRow == NewRows)) {\r
+ //\r
+ // Required text mode is supported, set it.\r
+ //\r
+ Status = SimpleTextOut->SetMode (SimpleTextOut, Index);\r
+ ASSERT_EFI_ERROR (Status);\r
+ //\r
+ // Update text mode PCD.\r
+ //\r
+ PcdSet32 (PcdConOutColumn, mSetupTextModeColumn);\r
+ PcdSet32 (PcdConOutRow, mSetupTextModeRow);\r
+ FreePool (Info);\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+ }\r
+ if (Index == MaxTextMode) {\r
+ //\r
+ // If requried text mode is not supported, return error.\r
+ //\r
+ FreePool (Info);\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ }\r
+ } else {\r
+ //\r
+ // If current video resolution is not same with the new one, set new video resolution.\r
+ // In this case, the driver which produces simple text out need be restarted.\r
+ //\r
+ Status = GraphicsOutput->SetMode (GraphicsOutput, ModeNumber);\r
+ if (!EFI_ERROR (Status)) {\r
+ FreePool (Info);\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ FreePool (Info);\r
+ }\r
+ }\r
+\r
+ if (ModeNumber == MaxGopMode) {\r
+ //\r
+ // If the resolution is not supported, return error.\r
+ //\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // Set PCD to Inform GraphicsConsole to change video resolution.\r
+ // Set PCD to Inform Consplitter to change text mode.\r
+ //\r
+ PcdSet32 (PcdVideoHorizontalResolution, NewHorizontalResolution);\r
+ PcdSet32 (PcdVideoVerticalResolution, NewVerticalResolution);\r
+ PcdSet32 (PcdConOutColumn, NewColumns);\r
+ PcdSet32 (PcdConOutRow, NewRows);\r
+ \r
+ \r
+ //\r
+ // Video mode is changed, so restart graphics console driver and higher level driver.\r
+ // Reconnect graphics console driver and higher level driver.\r
+ // Locate all the handles with GOP protocol and reconnect it.\r
+ //\r
+ Status = gBS->LocateHandleBuffer (\r
+ ByProtocol,\r
+ &gEfiSimpleTextOutProtocolGuid,\r
+ NULL,\r
+ &HandleCount,\r
+ &HandleBuffer\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ for (Index = 0; Index < HandleCount; Index++) {\r
+ gBS->DisconnectController (HandleBuffer[Index], NULL, NULL);\r
+ }\r
+ for (Index = 0; Index < HandleCount; Index++) {\r
+ gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE);\r
+ }\r
+ if (HandleBuffer != NULL) {\r
+ FreePool (HandleBuffer);\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Display the boot popup menu and allow user select boot item.\r
+\r
+ @param ImageHandle The image handle.\r
+ @param SystemTable The system table.\r
+ \r
+ @retval EFI_SUCCESS Boot from selected boot option, and return success from boot option\r
+ @retval EFI_NOT_FOUND User select to enter setup or can not find boot option\r
+ \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BootManagerMenuEntry (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOption;\r
+ UINTN BootOptionCount; \r
+ EFI_STATUS Status;\r
+ BOOT_MENU_POPUP_DATA BootMenuData;\r
+ UINTN Index;\r
+ EFI_INPUT_KEY Key;\r
+ BOOLEAN ExitApplication;\r
+ UINTN SelectItem;\r
+ EFI_BOOT_LOGO_PROTOCOL *BootLogo;\r
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;\r
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOut;\r
+ UINTN BootTextColumn;\r
+ UINTN BootTextRow;\r
+\r
+ //\r
+ // Set Logo status invalid when boot manager menu is launched\r
+ //\r
+ BootLogo = NULL;\r
+ Status = gBS->LocateProtocol (&gEfiBootLogoProtocolGuid, NULL, (VOID **) &BootLogo);\r
+ if (!EFI_ERROR (Status) && (BootLogo != NULL)) {\r
+ Status = BootLogo->SetBootLogo (BootLogo, NULL, 0, 0, 0, 0);\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+\r
+ gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);\r
+\r
+ gStringPackHandle = HiiAddPackages (\r
+ &gEfiCallerIdGuid,\r
+ gImageHandle,\r
+ BootManagerMenuAppStrings,\r
+ NULL\r
+ );\r
+ ASSERT (gStringPackHandle != NULL);\r
+\r
+ //\r
+ // Connect all prior to entering the platform setup menu.\r
+ //\r
+ EfiBootManagerConnectAll ();\r
+ EfiBootManagerRefreshAllBootOption ();\r
+\r
+ BootOption = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);\r
+\r
+ if (!mModeInitialized) {\r
+ //\r
+ // After the console is ready, get current video resolution \r
+ // and text mode before launching setup at first time.\r
+ //\r
+ Status = gBS->HandleProtocol (\r
+ gST->ConsoleOutHandle,\r
+ &gEfiGraphicsOutputProtocolGuid,\r
+ (VOID**)&GraphicsOutput\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ GraphicsOutput = NULL;\r
+ }\r
+ \r
+ Status = gBS->HandleProtocol (\r
+ gST->ConsoleOutHandle,\r
+ &gEfiSimpleTextOutProtocolGuid,\r
+ (VOID**)&SimpleTextOut\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ SimpleTextOut = NULL;\r
+ } \r
+\r
+ if (GraphicsOutput != NULL) {\r
+ //\r
+ // Get current video resolution and text mode.\r
+ //\r
+ mBootHorizontalResolution = GraphicsOutput->Mode->Info->HorizontalResolution;\r
+ mBootVerticalResolution = GraphicsOutput->Mode->Info->VerticalResolution;\r
+ }\r
+\r
+ if (SimpleTextOut != NULL) {\r
+ Status = SimpleTextOut->QueryMode (\r
+ SimpleTextOut,\r
+ SimpleTextOut->Mode->Mode,\r
+ &BootTextColumn,\r
+ &BootTextRow\r
+ );\r
+ mBootTextModeColumn = (UINT32)BootTextColumn;\r
+ mBootTextModeRow = (UINT32)BootTextRow;\r
+ }\r
+\r
+ //\r
+ // Get user defined text mode for setup.\r
+ // \r
+ mSetupHorizontalResolution = PcdGet32 (PcdSetupVideoHorizontalResolution);\r
+ mSetupVerticalResolution = PcdGet32 (PcdSetupVideoVerticalResolution); \r
+ mSetupTextModeColumn = PcdGet32 (PcdSetupConOutColumn);\r
+ mSetupTextModeRow = PcdGet32 (PcdSetupConOutRow);\r
+ mModeInitialized = TRUE;\r
+ }\r
+ \r
+ //\r
+ // Set back to conventional setup resolution\r
+ //\r
+ BdsSetConsoleMode (TRUE);\r
+\r
+ //\r
+ // Initialize Boot menu data\r
+ //\r
+ Status = InitializeBootMenuData (BootOption, BootOptionCount, &BootMenuData);\r
+ //\r
+ // According to boot menu data to draw boot popup menu\r
+ //\r
+ DrawBootPopupMenu (&BootMenuData);\r
+ \r
+ //\r
+ // check user input to determine want to re-draw or boot from user selected item\r
+ //\r
+ ExitApplication = FALSE;\r
+ while (!ExitApplication) {\r
+ gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &Index);\r
+ Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
+ if (!EFI_ERROR (Status)) {\r
+ switch (Key.UnicodeChar) {\r
+ \r
+ case CHAR_NULL: \r
+ switch (Key.ScanCode) { \r
+ \r
+ case SCAN_UP:\r
+ SelectItem = BootMenuData.SelectItem == 0 ? BootMenuData.ItemCount - 1 : BootMenuData.SelectItem - 1;\r
+ BootMenuSelectItem (SelectItem, &BootMenuData); \r
+ break;\r
+ \r
+ case SCAN_DOWN:\r
+ SelectItem = BootMenuData.SelectItem == BootMenuData.ItemCount - 1 ? 0 : BootMenuData.SelectItem + 1;\r
+ BootMenuSelectItem (SelectItem, &BootMenuData); \r
+ break;\r
+\r
+ case SCAN_ESC:\r
+ gST->ConOut->ClearScreen (gST->ConOut);\r
+ ExitApplication = TRUE;\r
+ //\r
+ // Set boot resolution for normal boot\r
+ //\r
+ BdsSetConsoleMode (FALSE);\r
+ break;\r
+ \r
+ default:\r
+ break;\r
+ }\r
+ break;\r
+ \r
+ case CHAR_CARRIAGE_RETURN:\r
+ gST->ConOut->ClearScreen (gST->ConOut);\r
+ //\r
+ // Set boot resolution for normal boot\r
+ //\r
+ BdsSetConsoleMode (FALSE);\r
+ BootFromSelectOption (BootOption, BootOptionCount, BootMenuData.SelectItem);\r
+ //\r
+ // Back to boot manager menu again, set back to setup resolution\r
+ //\r
+ BdsSetConsoleMode (TRUE);\r
+ DrawBootPopupMenu (&BootMenuData);\r
+ break;\r
+ \r
+ default:\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ EfiBootManagerFreeLoadOptions (BootOption, BootOptionCount);\r
+ FreePool (BootMenuData.PtrTokens);\r
+\r
+ HiiRemovePackages (gStringPackHandle);\r
+\r
+ return Status;\r
+ \r
+}\r