Home | History | Annotate | Download | only in BootManagerMenuApp
      1 /** @file
      2   The application to show the Boot Manager Menu.
      3 
      4 Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>
      5 This program and the accompanying materials
      6 are licensed and made available under the terms and conditions of the BSD License
      7 which accompanies this distribution.  The full text of the license may be found at
      8 http://opensource.org/licenses/bsd-license.php
      9 
     10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 #include "BootManagerMenu.h"
     16 
     17 EFI_HII_HANDLE gStringPackHandle;
     18 
     19 BOOLEAN   mModeInitialized = FALSE;
     20 
     21 //
     22 // Boot video resolution and text mode.
     23 //
     24 UINT32    mBootHorizontalResolution    = 0;
     25 UINT32    mBootVerticalResolution      = 0;
     26 UINT32    mBootTextModeColumn          = 0;
     27 UINT32    mBootTextModeRow             = 0;
     28 //
     29 // BIOS setup video resolution and text mode.
     30 //
     31 UINT32    mSetupTextModeColumn         = 0;
     32 UINT32    mSetupTextModeRow            = 0;
     33 UINT32    mSetupHorizontalResolution   = 0;
     34 UINT32    mSetupVerticalResolution     = 0;
     35 
     36 /**
     37   Prints a unicode string to the default console, at
     38   the supplied cursor position, using L"%s" format.
     39 
     40   @param  Column     The cursor position to print the string at.
     41   @param  Row        The cursor position to print the string at
     42   @param  String     String pointer.
     43 
     44   @return Length of string printed to the console
     45 
     46 **/
     47 UINTN
     48 PrintStringAt (
     49   IN UINTN     Column,
     50   IN UINTN     Row,
     51   IN CHAR16    *String
     52   )
     53 {
     54 
     55   gST->ConOut->SetCursorPosition (gST->ConOut, Column, Row);
     56   return Print (L"%s", String);
     57 }
     58 
     59 /**
     60   Prints a chracter to the default console, at
     61   the supplied cursor position, using L"%c" format.
     62 
     63   @param  Column     The cursor position to print the string at.
     64   @param  Row        The cursor position to print the string at.
     65   @param  Character  Character to print.
     66 
     67   @return Length of string printed to the console.
     68 
     69 **/
     70 UINTN
     71 PrintCharAt (
     72   IN UINTN     Column,
     73   IN UINTN     Row,
     74   CHAR16       Character
     75   )
     76 {
     77   gST->ConOut->SetCursorPosition (gST->ConOut, Column, Row);
     78   return Print (L"%c", Character);
     79 }
     80 
     81 /**
     82   Count the storage space of a Unicode string which uses current lanaguag to get
     83   from input string ID.
     84 
     85   @param StringId          The input string to be counted.
     86 
     87   @return Storage space for the input string.
     88 
     89 **/
     90 UINTN
     91 GetLineWidth (
     92   IN EFI_STRING_ID       StringId
     93   )
     94 {
     95   UINTN        Index;
     96   UINTN        IncrementValue;
     97   EFI_STRING   String;
     98   UINTN        LineWidth;
     99 
    100   LineWidth = 0;
    101   String = HiiGetString (gStringPackHandle, StringId, NULL);
    102 
    103   if (String != NULL) {
    104     Index           = 0;
    105     IncrementValue  = 1;
    106 
    107     do {
    108       //
    109       // Advance to the null-terminator or to the first width directive
    110       //
    111       for (;
    112            (String[Index] != NARROW_CHAR) && (String[Index] != WIDE_CHAR) && (String[Index] != 0);
    113            Index++, LineWidth = LineWidth + IncrementValue
    114           )
    115         ;
    116 
    117       //
    118       // We hit the null-terminator, we now have a count
    119       //
    120       if (String[Index] == 0) {
    121         break;
    122       }
    123       //
    124       // We encountered a narrow directive - strip it from the size calculation since it doesn't get printed
    125       // and also set the flag that determines what we increment by.(if narrow, increment by 1, if wide increment by 2)
    126       //
    127       if (String[Index] == NARROW_CHAR) {
    128         //
    129         // Skip to the next character
    130         //
    131         Index++;
    132         IncrementValue = 1;
    133       } else {
    134         //
    135         // Skip to the next character
    136         //
    137         Index++;
    138         IncrementValue = 2;
    139       }
    140     } while (String[Index] != 0);
    141     FreePool (String);
    142   }
    143 
    144   return LineWidth;
    145 }
    146 
    147 /**
    148   This function uses calculate the boot menu location, size and scroll bar information.
    149 
    150   @param  BootMenuData            The boot menu data to be proccessed.
    151 
    152   @return EFI_SUCCESS             calculate boot menu information successful.
    153   @retval EFI_INVALID_PARAMETER   Input parameter is invalid
    154 
    155 **/
    156 EFI_STATUS
    157 InitializeBootMenuScreen (
    158   IN OUT  BOOT_MENU_POPUP_DATA  *BootMenuData
    159   )
    160 {
    161   UINTN         MaxStrWidth;
    162   UINTN         StrWidth;
    163   UINTN         Index;
    164   UINTN         Column;
    165   UINTN         Row;
    166   UINTN         MaxPrintRows;
    167   UINTN         UnSelectableItmes;
    168 
    169   if (BootMenuData == NULL) {
    170     return EFI_INVALID_PARAMETER;
    171   }
    172   //
    173   // Get maximum string width
    174   //
    175   MaxStrWidth = 0;
    176   for (Index = 0; Index < TITLE_TOKEN_COUNT; Index++) {
    177     StrWidth = GetLineWidth (BootMenuData->TitleToken[Index]);
    178     MaxStrWidth = MaxStrWidth > StrWidth ? MaxStrWidth : StrWidth;
    179   }
    180 
    181   for (Index = 0; Index < BootMenuData->ItemCount; Index++) {
    182     StrWidth = GetLineWidth (BootMenuData->PtrTokens[Index]);
    183     MaxStrWidth = MaxStrWidth > StrWidth ? MaxStrWidth : StrWidth;
    184   }
    185 
    186   for (Index = 0; Index < HELP_TOKEN_COUNT; Index++) {
    187     StrWidth = GetLineWidth (BootMenuData->HelpToken[Index]);
    188     MaxStrWidth = MaxStrWidth > StrWidth ? MaxStrWidth : StrWidth;
    189   }
    190   //
    191   // query current row and column to calculate boot menu location
    192   //
    193   gST->ConOut->QueryMode (
    194                  gST->ConOut,
    195                  gST->ConOut->Mode->Mode,
    196                  &Column,
    197                  &Row
    198                  );
    199 
    200   MaxPrintRows = Row - 6;
    201   UnSelectableItmes = TITLE_TOKEN_COUNT + 2 + HELP_TOKEN_COUNT + 2;
    202   BootMenuData->MenuScreen.Width = MaxStrWidth + 8;
    203   if (BootMenuData->ItemCount + UnSelectableItmes > MaxPrintRows) {
    204     BootMenuData->MenuScreen.Height = MaxPrintRows;
    205     BootMenuData->ScrollBarControl.HasScrollBar = TRUE;
    206     BootMenuData->ScrollBarControl.ItemCountPerScreen = MaxPrintRows - UnSelectableItmes;
    207     BootMenuData->ScrollBarControl.FirstItem = 0;
    208     BootMenuData->ScrollBarControl.LastItem = MaxPrintRows - UnSelectableItmes - 1;
    209   } else {
    210     BootMenuData->MenuScreen.Height = BootMenuData->ItemCount + UnSelectableItmes;
    211     BootMenuData->ScrollBarControl.HasScrollBar = FALSE;
    212     BootMenuData->ScrollBarControl.ItemCountPerScreen = BootMenuData->ItemCount;
    213     BootMenuData->ScrollBarControl.FirstItem = 0;
    214     BootMenuData->ScrollBarControl.LastItem = BootMenuData->ItemCount - 1;
    215   }
    216   BootMenuData->MenuScreen.StartCol = (Column -  BootMenuData->MenuScreen.Width) / 2;
    217   BootMenuData->MenuScreen.StartRow = (Row -  BootMenuData->MenuScreen.Height) / 2;
    218 
    219   return EFI_SUCCESS;
    220 }
    221 /**
    222   This funciton uses check boot option is wheher setup application or no
    223 
    224   @param   BootOption   Pointer to EFI_BOOT_MANAGER_LOAD_OPTION array.
    225 
    226   @retval  TRUE         This boot option is setup application.
    227   @retval  FALSE        This boot options isn't setup application
    228 
    229 **/
    230 BOOLEAN
    231 IsBootManagerMenu (
    232   IN  EFI_BOOT_MANAGER_LOAD_OPTION    *BootOption
    233   )
    234 {
    235   EFI_STATUS                          Status;
    236   EFI_BOOT_MANAGER_LOAD_OPTION        BootManagerMenu;
    237 
    238   Status = EfiBootManagerGetBootManagerMenu (&BootManagerMenu);
    239   if (!EFI_ERROR (Status)) {
    240     EfiBootManagerFreeLoadOption (&BootManagerMenu);
    241   }
    242 
    243   return (BOOLEAN) (!EFI_ERROR (Status) && (BootOption->OptionNumber == BootManagerMenu.OptionNumber));
    244 }
    245 
    246 /**
    247   Return whether to ignore the boot option.
    248 
    249   @param BootOption  Pointer to EFI_BOOT_MANAGER_LOAD_OPTION to check.
    250 
    251   @retval TRUE  Ignore the boot optin.
    252   @retval FALSE Do not ignore the boot option.
    253 **/
    254 BOOLEAN
    255 IgnoreBootOption (
    256   IN   EFI_BOOT_MANAGER_LOAD_OPTION  *BootOption
    257   )
    258 {
    259   EFI_STATUS                    Status;
    260   EFI_DEVICE_PATH_PROTOCOL      *ImageDevicePath;
    261 
    262   //
    263   // Ignore myself.
    264   //
    265   Status = gBS->HandleProtocol (gImageHandle, &gEfiLoadedImageDevicePathProtocolGuid, (VOID **) &ImageDevicePath);
    266   ASSERT_EFI_ERROR (Status);
    267   if (CompareMem (BootOption->FilePath, ImageDevicePath, GetDevicePathSize (ImageDevicePath)) == 0) {
    268     return TRUE;
    269   }
    270 
    271   //
    272   // Do not ignore Boot Manager Menu.
    273   //
    274   if (IsBootManagerMenu (BootOption)) {
    275     return FALSE;
    276   }
    277 
    278   //
    279   // Ignore the hidden/inactive boot option.
    280   //
    281   if (((BootOption->Attributes & LOAD_OPTION_HIDDEN) != 0) || ((BootOption->Attributes & LOAD_OPTION_ACTIVE) == 0)) {
    282     return TRUE;
    283   }
    284 
    285   return FALSE;
    286 }
    287 
    288 /**
    289   This funciton uses to initialize boot menu data
    290 
    291   @param   BootOption             Pointer to EFI_BOOT_MANAGER_LOAD_OPTION array.
    292   @param   BootOptionCount        Number of boot option.
    293   @param   BootMenuData           The Input BootMenuData to be initialized.
    294 
    295   @retval  EFI_SUCCESS            Initialize boot menu data successful.
    296   @retval  EFI_INVALID_PARAMETER  Input parameter is invalid.
    297 
    298 **/
    299 EFI_STATUS
    300 InitializeBootMenuData (
    301   IN   EFI_BOOT_MANAGER_LOAD_OPTION  *BootOption,
    302   IN   UINTN                         BootOptionCount,
    303   OUT  BOOT_MENU_POPUP_DATA          *BootMenuData
    304   )
    305 {
    306   UINTN                         Index;
    307   UINTN                         StrIndex;
    308 
    309   if (BootOption == NULL || BootMenuData == NULL) {
    310     return EFI_INVALID_PARAMETER;
    311   }
    312 
    313   BootMenuData->TitleToken[0] = STRING_TOKEN (STR_BOOT_POPUP_MENU_TITLE_STRING);
    314   BootMenuData->PtrTokens     = AllocateZeroPool (BootOptionCount * sizeof (EFI_STRING_ID));
    315   ASSERT (BootMenuData->PtrTokens != NULL);
    316 
    317   //
    318   // Skip boot option which created by BootNext Variable
    319   //
    320   for (StrIndex = 0, Index = 0; Index < BootOptionCount; Index++) {
    321     if (IgnoreBootOption (&BootOption[Index])) {
    322       continue;
    323     }
    324 
    325     ASSERT (BootOption[Index].Description != NULL);
    326     BootMenuData->PtrTokens[StrIndex++] = HiiSetString (
    327                                             gStringPackHandle,
    328                                             0,
    329                                             BootOption[Index].Description,
    330                                             NULL
    331                                             );
    332   }
    333 
    334   BootMenuData->ItemCount           = StrIndex;
    335   BootMenuData->HelpToken[0] = STRING_TOKEN (STR_BOOT_POPUP_MENU_HELP1_STRING);
    336   BootMenuData->HelpToken[1] = STRING_TOKEN (STR_BOOT_POPUP_MENU_HELP2_STRING);
    337   BootMenuData->HelpToken[2] = STRING_TOKEN (STR_BOOT_POPUP_MENU_HELP3_STRING);
    338   InitializeBootMenuScreen (BootMenuData);
    339   BootMenuData->SelectItem = 0;
    340   return EFI_SUCCESS;
    341 }
    342 
    343 /**
    344   This function uses input select item to highlight selected item
    345   and set current selected item in BootMenuData
    346 
    347   @param  WantSelectItem          The user wants to select item.
    348   @param  BootMenuData            The boot menu data to be proccessed
    349 
    350   @return EFI_SUCCESS             Highlight selected item and update current selected
    351                                   item successful
    352   @retval EFI_INVALID_PARAMETER   Input parameter is invalid
    353 **/
    354 EFI_STATUS
    355 BootMenuSelectItem (
    356   IN     UINTN                 WantSelectItem,
    357   IN OUT BOOT_MENU_POPUP_DATA  *BootMenuData
    358   )
    359 {
    360   INT32                 SavedAttribute;
    361   EFI_STRING            String;
    362   UINTN                 StartCol;
    363   UINTN                 StartRow;
    364   UINTN                 PrintCol;
    365   UINTN                 PrintRow;
    366   UINTN                 TopShadeNum;
    367   UINTN                 LowShadeNum;
    368   UINTN                 FirstItem;
    369   UINTN                 LastItem;
    370   UINTN                 ItemCountPerScreen;
    371   UINTN                 Index;
    372   BOOLEAN               RePaintItems;
    373 
    374   if (BootMenuData == NULL || WantSelectItem >= BootMenuData->ItemCount) {
    375     return EFI_INVALID_PARAMETER;
    376   }
    377   SavedAttribute = gST->ConOut->Mode->Attribute;
    378   RePaintItems = FALSE;
    379   StartCol = BootMenuData->MenuScreen.StartCol;
    380   StartRow = BootMenuData->MenuScreen.StartRow;
    381   //
    382   // print selectable items again and adjust scroll bar if need
    383   //
    384   if (BootMenuData->ScrollBarControl.HasScrollBar &&
    385       (WantSelectItem < BootMenuData->ScrollBarControl.FirstItem ||
    386       WantSelectItem > BootMenuData->ScrollBarControl.LastItem ||
    387       WantSelectItem == BootMenuData->SelectItem)) {
    388     ItemCountPerScreen   = BootMenuData->ScrollBarControl.ItemCountPerScreen;
    389     //
    390     // Set first item and last item
    391     //
    392     if (WantSelectItem < BootMenuData->ScrollBarControl.FirstItem) {
    393       BootMenuData->ScrollBarControl.FirstItem = WantSelectItem;
    394       BootMenuData->ScrollBarControl.LastItem = WantSelectItem + ItemCountPerScreen - 1;
    395     } else if (WantSelectItem > BootMenuData->ScrollBarControl.LastItem) {
    396       BootMenuData->ScrollBarControl.FirstItem = WantSelectItem - ItemCountPerScreen + 1;
    397       BootMenuData->ScrollBarControl.LastItem = WantSelectItem;
    398     }
    399     gST->ConOut->SetAttribute (gST->ConOut, EFI_WHITE | EFI_BACKGROUND_BLUE);
    400     FirstItem = BootMenuData->ScrollBarControl.FirstItem;
    401     LastItem  = BootMenuData->ScrollBarControl.LastItem;
    402     TopShadeNum = 0;
    403     if (FirstItem != 0) {
    404       TopShadeNum = (FirstItem * ItemCountPerScreen) / BootMenuData->ItemCount;
    405       if ((FirstItem * ItemCountPerScreen) % BootMenuData->ItemCount != 0) {
    406         TopShadeNum++;
    407       }
    408       PrintCol = StartCol  + BootMenuData->MenuScreen.Width - 2;
    409       PrintRow = StartRow + TITLE_TOKEN_COUNT + 2;
    410       for (Index = 0; Index < TopShadeNum; Index++, PrintRow++) {
    411         PrintCharAt (PrintCol, PrintRow, BLOCKELEMENT_LIGHT_SHADE);
    412       }
    413     }
    414     LowShadeNum = 0;
    415     if (LastItem != BootMenuData->ItemCount - 1) {
    416       LowShadeNum = ((BootMenuData->ItemCount - 1 - LastItem) * ItemCountPerScreen) / BootMenuData->ItemCount;
    417       if (((BootMenuData->ItemCount - 1 - LastItem) * ItemCountPerScreen) % BootMenuData->ItemCount != 0) {
    418         LowShadeNum++;
    419       }
    420       PrintCol = StartCol  + BootMenuData->MenuScreen.Width - 2;
    421       PrintRow = StartRow + TITLE_TOKEN_COUNT + 2 + ItemCountPerScreen - LowShadeNum;
    422       for (Index = 0; Index < LowShadeNum; Index++, PrintRow++) {
    423         PrintCharAt (PrintCol, PrintRow, BLOCKELEMENT_LIGHT_SHADE);
    424       }
    425     }
    426     PrintCol = StartCol  + BootMenuData->MenuScreen.Width - 2;
    427     PrintRow = StartRow + TITLE_TOKEN_COUNT + 2 + TopShadeNum;
    428     for (Index = TopShadeNum; Index < ItemCountPerScreen - LowShadeNum; Index++, PrintRow++) {
    429       PrintCharAt (PrintCol, PrintRow, BLOCKELEMENT_FULL_BLOCK);
    430     }
    431 
    432 
    433     //
    434     // Clear selectable items first
    435     //
    436     PrintCol = StartCol  + 1;
    437     PrintRow = StartRow + TITLE_TOKEN_COUNT + 2;
    438     String = AllocateZeroPool ((BootMenuData->MenuScreen.Width - 2) * sizeof (CHAR16));
    439     ASSERT (String != NULL);
    440     for (Index = 0; Index < BootMenuData->MenuScreen.Width - 3; Index++) {
    441       String[Index] = 0x20;
    442     }
    443     for (Index = 0; Index < ItemCountPerScreen; Index++) {
    444       PrintStringAt (PrintCol, PrintRow + Index, String);
    445     }
    446     FreePool (String);
    447     //
    448     // print selectable items
    449     //
    450     for (Index = 0; Index < ItemCountPerScreen; Index++, PrintRow++) {
    451       String = HiiGetString (gStringPackHandle, BootMenuData->PtrTokens[Index + FirstItem], NULL);
    452       PrintStringAt (PrintCol, PrintRow, String);
    453       FreePool (String);
    454     }
    455     RePaintItems = TRUE;
    456   }
    457 
    458   //
    459   // Print want to select item
    460   //
    461   FirstItem = BootMenuData->ScrollBarControl.FirstItem;
    462   gST->ConOut->SetAttribute (gST->ConOut, EFI_WHITE | EFI_BACKGROUND_BLACK);
    463   String = HiiGetString (gStringPackHandle, BootMenuData->PtrTokens[WantSelectItem], NULL);
    464   PrintCol = StartCol  + 1;
    465   PrintRow = StartRow + TITLE_TOKEN_COUNT + 2 + WantSelectItem - FirstItem;
    466   PrintStringAt (PrintCol, PrintRow, String);
    467   FreePool (String);
    468 
    469   //
    470   // if Want Select and selected item isn't the same and doesn't re-draw selectable
    471   // items, clear select item
    472   //
    473   if (WantSelectItem != BootMenuData->SelectItem && !RePaintItems) {
    474     gST->ConOut->SetAttribute (gST->ConOut, EFI_WHITE | EFI_BACKGROUND_BLUE);
    475     String = HiiGetString (gStringPackHandle, BootMenuData->PtrTokens[BootMenuData->SelectItem], NULL);
    476     PrintCol = StartCol  + 1;
    477     PrintRow = StartRow + 3 + BootMenuData->SelectItem - FirstItem;
    478     PrintStringAt (PrintCol, PrintRow, String);
    479     FreePool (String);
    480   }
    481 
    482   gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute);
    483   BootMenuData->SelectItem = WantSelectItem;
    484   return EFI_SUCCESS;
    485 }
    486 
    487 /**
    488   This funciton uses to draw boot popup menu
    489 
    490   @param   BootMenuData           The Input BootMenuData to be processed.
    491 
    492   @retval  EFI_SUCCESS            Draw boot popup menu successful.
    493 
    494 **/
    495 EFI_STATUS
    496 DrawBootPopupMenu (
    497   IN  BOOT_MENU_POPUP_DATA  *BootMenuData
    498   )
    499 {
    500   EFI_STRING            String;
    501   UINTN                 Index;
    502   UINTN                 Width;
    503   UINTN                 Height;
    504   UINTN                 StartCol;
    505   UINTN                 StartRow;
    506   UINTN                 PrintRow;
    507   UINTN                 PrintCol;
    508   UINTN                 LineWidth;
    509   INT32                 SavedAttribute;
    510   UINTN                 ItemCountPerScreen;
    511 
    512   gST->ConOut->ClearScreen (gST->ConOut);
    513 
    514   SavedAttribute = gST->ConOut->Mode->Attribute;
    515   gST->ConOut->SetAttribute (gST->ConOut, EFI_WHITE | EFI_BACKGROUND_BLUE);
    516   Width    = BootMenuData->MenuScreen.Width;
    517   Height   = BootMenuData->MenuScreen.Height;
    518   StartCol = BootMenuData->MenuScreen.StartCol;
    519   StartRow = BootMenuData->MenuScreen.StartRow;
    520   ItemCountPerScreen = BootMenuData->ScrollBarControl.ItemCountPerScreen;
    521   PrintRow = StartRow;
    522 
    523   gST->ConOut->EnableCursor (gST->ConOut, FALSE);
    524   //
    525   // Draw Boot popup menu screen
    526   //
    527   PrintCharAt (StartCol, PrintRow, BOXDRAW_DOWN_RIGHT);
    528   for (Index = 1; Index < Width - 1; Index++) {
    529     PrintCharAt (StartCol + Index, PrintRow, BOXDRAW_HORIZONTAL);
    530   }
    531   PrintCharAt (StartCol + Width - 1, PrintRow, BOXDRAW_DOWN_LEFT);
    532 
    533   //
    534   // Draw the screen for title
    535   //
    536   String = AllocateZeroPool ((Width - 1) * sizeof (CHAR16));
    537   ASSERT (String != NULL);
    538   for (Index = 0; Index < Width - 2; Index++) {
    539     String[Index] = 0x20;
    540   }
    541 
    542   for (Index = 0; Index < TITLE_TOKEN_COUNT; Index++) {
    543     PrintRow++;
    544     PrintCharAt (StartCol, PrintRow, BOXDRAW_VERTICAL);
    545     PrintStringAt (StartCol + 1, PrintRow, String);
    546     PrintCharAt (StartCol + Width - 1, PrintRow, BOXDRAW_VERTICAL);
    547   }
    548 
    549   PrintRow++;
    550   PrintCharAt (StartCol, PrintRow, BOXDRAW_VERTICAL_RIGHT);
    551   for (Index = 1; Index < Width - 1; Index++) {
    552     PrintCharAt (StartCol + Index, PrintRow, BOXDRAW_HORIZONTAL);
    553   }
    554   PrintCharAt (StartCol + Width - 1, PrintRow, BOXDRAW_VERTICAL_LEFT);
    555 
    556   //
    557   // Draw screen for selectable items
    558   //
    559   for (Index = 0; Index < ItemCountPerScreen; Index++) {
    560     PrintRow++;
    561     PrintCharAt (StartCol, PrintRow, BOXDRAW_VERTICAL);
    562     PrintStringAt (StartCol + 1, PrintRow, String);
    563     PrintCharAt (StartCol + Width - 1, PrintRow, BOXDRAW_VERTICAL);
    564   }
    565 
    566   PrintRow++;
    567   PrintCharAt (StartCol, PrintRow, BOXDRAW_VERTICAL_RIGHT);
    568   for (Index = 1; Index < Width - 1; Index++) {
    569     PrintCharAt (StartCol + Index, PrintRow, BOXDRAW_HORIZONTAL);
    570   }
    571   PrintCharAt (StartCol + Width - 1, PrintRow, BOXDRAW_VERTICAL_LEFT);
    572 
    573   //
    574   // Draw screen for Help
    575   //
    576   for (Index = 0; Index < HELP_TOKEN_COUNT; Index++) {
    577     PrintRow++;
    578     PrintCharAt (StartCol, PrintRow, BOXDRAW_VERTICAL);
    579     PrintStringAt (StartCol + 1, PrintRow, String);
    580     PrintCharAt (StartCol + Width - 1, PrintRow, BOXDRAW_VERTICAL);
    581   }
    582   FreePool (String);
    583 
    584   PrintRow++;
    585   PrintCharAt (StartCol, PrintRow, BOXDRAW_UP_RIGHT);
    586   for (Index = 1; Index < Width - 1; Index++) {
    587     PrintCharAt (StartCol + Index, PrintRow, BOXDRAW_HORIZONTAL);
    588   }
    589   PrintCharAt (StartCol + Width - 1, PrintRow, BOXDRAW_UP_LEFT);
    590 
    591 
    592   //
    593   // print title strings
    594   //
    595   PrintRow = StartRow + 1;
    596   for (Index = 0; Index < TITLE_TOKEN_COUNT; Index++, PrintRow++) {
    597     String = HiiGetString (gStringPackHandle, BootMenuData->TitleToken[Index], NULL);
    598     LineWidth = GetLineWidth (BootMenuData->TitleToken[Index]);
    599     PrintCol = StartCol + (Width - LineWidth) / 2;
    600     PrintStringAt (PrintCol, PrintRow, String);
    601     FreePool (String);
    602   }
    603 
    604   //
    605   // print selectable items
    606   //
    607   PrintCol = StartCol + 1;
    608   PrintRow = StartRow + TITLE_TOKEN_COUNT + 2;
    609   for (Index = 0; Index < ItemCountPerScreen; Index++, PrintRow++) {
    610     String = HiiGetString (gStringPackHandle, BootMenuData->PtrTokens[Index], NULL);
    611     PrintStringAt (PrintCol, PrintRow, String);
    612     FreePool (String);
    613   }
    614 
    615   //
    616   // Print Help strings
    617   //
    618   PrintRow++;
    619   for (Index = 0; Index < HELP_TOKEN_COUNT; Index++, PrintRow++) {
    620     String = HiiGetString (gStringPackHandle, BootMenuData->HelpToken[Index], NULL);
    621     LineWidth = GetLineWidth (BootMenuData->HelpToken[Index]);
    622     PrintCol = StartCol + (Width - LineWidth) / 2;
    623     PrintStringAt (PrintCol, PrintRow, String);
    624     FreePool (String);
    625   }
    626 
    627   //
    628   // Print scroll bar if has scroll bar
    629   //
    630   if (BootMenuData->ScrollBarControl.HasScrollBar) {
    631     PrintCol = StartCol + Width - 2;
    632     PrintRow = StartRow + 2;
    633     PrintCharAt (PrintCol, PrintRow, GEOMETRICSHAPE_UP_TRIANGLE);
    634     PrintCharAt (PrintCol + 1, PrintRow, BOXDRAW_VERTICAL);
    635     PrintRow += (ItemCountPerScreen + 1);
    636     PrintCharAt (PrintCol, PrintRow, GEOMETRICSHAPE_DOWN_TRIANGLE);
    637     PrintCharAt (PrintCol + 1, PrintRow, BOXDRAW_VERTICAL);
    638   }
    639 
    640   gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute);
    641   //
    642   // Print Selected item
    643   //
    644   BootMenuSelectItem (BootMenuData->SelectItem, BootMenuData);
    645   return EFI_SUCCESS;
    646 }
    647 
    648 /**
    649   This funciton uses to boot from selected item
    650 
    651   @param   BootOptions            Pointer to EFI_BOOT_MANAGER_LOAD_OPTION array.
    652   @param   BootOptionCount        Number of boot option.
    653   @param   SelectItem             Current selected item.
    654 **/
    655 VOID
    656 BootFromSelectOption (
    657   IN   EFI_BOOT_MANAGER_LOAD_OPTION  *BootOptions,
    658   IN   UINTN                         BootOptionCount,
    659   IN   UINTN                         SelectItem
    660   )
    661 {
    662   UINTN                 ItemNum;
    663   UINTN                 Index;
    664 
    665   ASSERT (BootOptions != NULL);
    666 
    667   for (ItemNum = 0, Index = 0; Index < BootOptionCount; Index++) {
    668     if (IgnoreBootOption (&BootOptions[Index])) {
    669       continue;
    670     }
    671 
    672     if (ItemNum++ == SelectItem) {
    673       EfiBootManagerBoot (&BootOptions[Index]);
    674       break;
    675     }
    676   }
    677 }
    678 
    679 /**
    680   This function will change video resolution and text mode
    681   according to defined setup mode or defined boot mode
    682 
    683   @param  IsSetupMode   Indicate mode is changed to setup mode or boot mode.
    684 
    685   @retval  EFI_SUCCESS  Mode is changed successfully.
    686   @retval  Others             Mode failed to be changed.
    687 
    688 **/
    689 EFI_STATUS
    690 EFIAPI
    691 BdsSetConsoleMode (
    692   BOOLEAN  IsSetupMode
    693   )
    694 {
    695   EFI_GRAPHICS_OUTPUT_PROTOCOL          *GraphicsOutput;
    696   EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL       *SimpleTextOut;
    697   UINTN                                 SizeOfInfo;
    698   EFI_GRAPHICS_OUTPUT_MODE_INFORMATION  *Info;
    699   UINT32                                MaxGopMode;
    700   UINT32                                MaxTextMode;
    701   UINT32                                ModeNumber;
    702   UINT32                                NewHorizontalResolution;
    703   UINT32                                NewVerticalResolution;
    704   UINT32                                NewColumns;
    705   UINT32                                NewRows;
    706   UINTN                                 HandleCount;
    707   EFI_HANDLE                            *HandleBuffer;
    708   EFI_STATUS                            Status;
    709   UINTN                                 Index;
    710   UINTN                                 CurrentColumn;
    711   UINTN                                 CurrentRow;
    712 
    713   MaxGopMode  = 0;
    714   MaxTextMode = 0;
    715 
    716   //
    717   // Get current video resolution and text mode
    718   //
    719   Status = gBS->HandleProtocol (
    720                   gST->ConsoleOutHandle,
    721                   &gEfiGraphicsOutputProtocolGuid,
    722                   (VOID**)&GraphicsOutput
    723                   );
    724   if (EFI_ERROR (Status)) {
    725     GraphicsOutput = NULL;
    726   }
    727 
    728   Status = gBS->HandleProtocol (
    729                   gST->ConsoleOutHandle,
    730                   &gEfiSimpleTextOutProtocolGuid,
    731                   (VOID**)&SimpleTextOut
    732                   );
    733   if (EFI_ERROR (Status)) {
    734     SimpleTextOut = NULL;
    735   }
    736 
    737   if ((GraphicsOutput == NULL) || (SimpleTextOut == NULL)) {
    738     return EFI_UNSUPPORTED;
    739   }
    740 
    741   if (IsSetupMode) {
    742     //
    743     // The requried resolution and text mode is setup mode.
    744     //
    745     NewHorizontalResolution = mSetupHorizontalResolution;
    746     NewVerticalResolution   = mSetupVerticalResolution;
    747     NewColumns              = mSetupTextModeColumn;
    748     NewRows                 = mSetupTextModeRow;
    749   } else {
    750     //
    751     // The required resolution and text mode is boot mode.
    752     //
    753     NewHorizontalResolution = mBootHorizontalResolution;
    754     NewVerticalResolution   = mBootVerticalResolution;
    755     NewColumns              = mBootTextModeColumn;
    756     NewRows                 = mBootTextModeRow;
    757   }
    758 
    759   if (GraphicsOutput != NULL) {
    760     MaxGopMode  = GraphicsOutput->Mode->MaxMode;
    761   }
    762 
    763   if (SimpleTextOut != NULL) {
    764     MaxTextMode = SimpleTextOut->Mode->MaxMode;
    765   }
    766 
    767   //
    768   // 1. If current video resolution is same with required video resolution,
    769   //    video resolution need not be changed.
    770   //    1.1. If current text mode is same with required text mode, text mode need not be changed.
    771   //    1.2. If current text mode is different from required text mode, text mode need be changed.
    772   // 2. If current video resolution is different from required video resolution, we need restart whole console drivers.
    773   //
    774   for (ModeNumber = 0; ModeNumber < MaxGopMode; ModeNumber++) {
    775     Status = GraphicsOutput->QueryMode (
    776                        GraphicsOutput,
    777                        ModeNumber,
    778                        &SizeOfInfo,
    779                        &Info
    780                        );
    781     if (!EFI_ERROR (Status)) {
    782       if ((Info->HorizontalResolution == NewHorizontalResolution) &&
    783           (Info->VerticalResolution == NewVerticalResolution)) {
    784         if ((GraphicsOutput->Mode->Info->HorizontalResolution == NewHorizontalResolution) &&
    785             (GraphicsOutput->Mode->Info->VerticalResolution == NewVerticalResolution)) {
    786           //
    787           // Current resolution is same with required resolution, check if text mode need be set
    788           //
    789           Status = SimpleTextOut->QueryMode (SimpleTextOut, SimpleTextOut->Mode->Mode, &CurrentColumn, &CurrentRow);
    790           ASSERT_EFI_ERROR (Status);
    791           if (CurrentColumn == NewColumns && CurrentRow == NewRows) {
    792             //
    793             // If current text mode is same with required text mode. Do nothing
    794             //
    795             FreePool (Info);
    796             return EFI_SUCCESS;
    797           } else {
    798             //
    799             // If current text mode is different from requried text mode.  Set new video mode
    800             //
    801             for (Index = 0; Index < MaxTextMode; Index++) {
    802               Status = SimpleTextOut->QueryMode (SimpleTextOut, Index, &CurrentColumn, &CurrentRow);
    803               if (!EFI_ERROR(Status)) {
    804                 if ((CurrentColumn == NewColumns) && (CurrentRow == NewRows)) {
    805                   //
    806                   // Required text mode is supported, set it.
    807                   //
    808                   Status = SimpleTextOut->SetMode (SimpleTextOut, Index);
    809                   ASSERT_EFI_ERROR (Status);
    810                   //
    811                   // Update text mode PCD.
    812                   //
    813                   Status = PcdSet32S (PcdConOutColumn, mSetupTextModeColumn);
    814                   ASSERT_EFI_ERROR (Status);
    815                   Status = PcdSet32S (PcdConOutRow, mSetupTextModeRow);
    816                   ASSERT_EFI_ERROR (Status);
    817                   FreePool (Info);
    818                   return EFI_SUCCESS;
    819                 }
    820               }
    821             }
    822             if (Index == MaxTextMode) {
    823               //
    824               // If requried text mode is not supported, return error.
    825               //
    826               FreePool (Info);
    827               return EFI_UNSUPPORTED;
    828             }
    829           }
    830         } else {
    831           //
    832           // If current video resolution is not same with the new one, set new video resolution.
    833           // In this case, the driver which produces simple text out need be restarted.
    834           //
    835           Status = GraphicsOutput->SetMode (GraphicsOutput, ModeNumber);
    836           if (!EFI_ERROR (Status)) {
    837             FreePool (Info);
    838             break;
    839           }
    840         }
    841       }
    842       FreePool (Info);
    843     }
    844   }
    845 
    846   if (ModeNumber == MaxGopMode) {
    847     //
    848     // If the resolution is not supported, return error.
    849     //
    850     return EFI_UNSUPPORTED;
    851   }
    852 
    853   //
    854   // Set PCD to Inform GraphicsConsole to change video resolution.
    855   // Set PCD to Inform Consplitter to change text mode.
    856   //
    857   Status = PcdSet32S (PcdVideoHorizontalResolution, NewHorizontalResolution);
    858   ASSERT_EFI_ERROR (Status);
    859   Status = PcdSet32S (PcdVideoVerticalResolution, NewVerticalResolution);
    860   ASSERT_EFI_ERROR (Status);
    861   Status = PcdSet32S (PcdConOutColumn, NewColumns);
    862   ASSERT_EFI_ERROR (Status);
    863   Status = PcdSet32S (PcdConOutRow, NewRows);
    864   ASSERT_EFI_ERROR (Status);
    865 
    866   //
    867   // Video mode is changed, so restart graphics console driver and higher level driver.
    868   // Reconnect graphics console driver and higher level driver.
    869   // Locate all the handles with GOP protocol and reconnect it.
    870   //
    871   Status = gBS->LocateHandleBuffer (
    872                    ByProtocol,
    873                    &gEfiSimpleTextOutProtocolGuid,
    874                    NULL,
    875                    &HandleCount,
    876                    &HandleBuffer
    877                    );
    878   if (!EFI_ERROR (Status)) {
    879     for (Index = 0; Index < HandleCount; Index++) {
    880       gBS->DisconnectController (HandleBuffer[Index], NULL, NULL);
    881     }
    882     for (Index = 0; Index < HandleCount; Index++) {
    883       gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE);
    884     }
    885     if (HandleBuffer != NULL) {
    886       FreePool (HandleBuffer);
    887     }
    888   }
    889 
    890   return EFI_SUCCESS;
    891 }
    892 
    893 /**
    894   Display the boot popup menu and allow user select boot item.
    895 
    896   @param   ImageHandle     The image handle.
    897   @param   SystemTable     The system table.
    898 
    899   @retval  EFI_SUCCESS          Boot from selected boot option, and return success from boot option
    900   @retval  EFI_NOT_FOUND        User select to enter setup or can not find boot option
    901 
    902 **/
    903 EFI_STATUS
    904 EFIAPI
    905 BootManagerMenuEntry (
    906   IN EFI_HANDLE                            ImageHandle,
    907   IN EFI_SYSTEM_TABLE                      *SystemTable
    908   )
    909 {
    910   EFI_BOOT_MANAGER_LOAD_OPTION    *BootOption;
    911   UINTN                           BootOptionCount;
    912   EFI_STATUS                      Status;
    913   BOOT_MENU_POPUP_DATA            BootMenuData;
    914   UINTN                           Index;
    915   EFI_INPUT_KEY                   Key;
    916   BOOLEAN                         ExitApplication;
    917   UINTN                           SelectItem;
    918   EFI_BOOT_LOGO_PROTOCOL          *BootLogo;
    919   EFI_GRAPHICS_OUTPUT_PROTOCOL    *GraphicsOutput;
    920   EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOut;
    921   UINTN                           BootTextColumn;
    922   UINTN                           BootTextRow;
    923 
    924   //
    925   // Set Logo status invalid when boot manager menu is launched
    926   //
    927   BootLogo = NULL;
    928   Status = gBS->LocateProtocol (&gEfiBootLogoProtocolGuid, NULL, (VOID **) &BootLogo);
    929   if (!EFI_ERROR (Status) && (BootLogo != NULL)) {
    930     Status = BootLogo->SetBootLogo (BootLogo, NULL, 0, 0, 0, 0);
    931     ASSERT_EFI_ERROR (Status);
    932   }
    933 
    934   gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);
    935 
    936   gStringPackHandle = HiiAddPackages (
    937                          &gEfiCallerIdGuid,
    938                          gImageHandle,
    939                          BootManagerMenuAppStrings,
    940                          NULL
    941                          );
    942   ASSERT (gStringPackHandle != NULL);
    943 
    944   //
    945   // Connect all prior to entering the platform setup menu.
    946   //
    947   EfiBootManagerConnectAll ();
    948   EfiBootManagerRefreshAllBootOption ();
    949 
    950   BootOption = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
    951 
    952   if (!mModeInitialized) {
    953     //
    954     // After the console is ready, get current video resolution
    955     // and text mode before launching setup at first time.
    956     //
    957     Status = gBS->HandleProtocol (
    958                     gST->ConsoleOutHandle,
    959                     &gEfiGraphicsOutputProtocolGuid,
    960                     (VOID**)&GraphicsOutput
    961                     );
    962     if (EFI_ERROR (Status)) {
    963       GraphicsOutput = NULL;
    964     }
    965 
    966     Status = gBS->HandleProtocol (
    967                     gST->ConsoleOutHandle,
    968                     &gEfiSimpleTextOutProtocolGuid,
    969                     (VOID**)&SimpleTextOut
    970                     );
    971     if (EFI_ERROR (Status)) {
    972       SimpleTextOut = NULL;
    973     }
    974 
    975     if (GraphicsOutput != NULL) {
    976       //
    977       // Get current video resolution and text mode.
    978       //
    979       mBootHorizontalResolution = GraphicsOutput->Mode->Info->HorizontalResolution;
    980       mBootVerticalResolution   = GraphicsOutput->Mode->Info->VerticalResolution;
    981     }
    982 
    983     if (SimpleTextOut != NULL) {
    984       Status = SimpleTextOut->QueryMode (
    985                                 SimpleTextOut,
    986                                 SimpleTextOut->Mode->Mode,
    987                                 &BootTextColumn,
    988                                 &BootTextRow
    989                                 );
    990       mBootTextModeColumn = (UINT32)BootTextColumn;
    991       mBootTextModeRow    = (UINT32)BootTextRow;
    992     }
    993 
    994     //
    995     // Get user defined text mode for setup.
    996     //
    997     mSetupHorizontalResolution = PcdGet32 (PcdSetupVideoHorizontalResolution);
    998     mSetupVerticalResolution   = PcdGet32 (PcdSetupVideoVerticalResolution);
    999     mSetupTextModeColumn       = PcdGet32 (PcdSetupConOutColumn);
   1000     mSetupTextModeRow          = PcdGet32 (PcdSetupConOutRow);
   1001     mModeInitialized           = TRUE;
   1002   }
   1003 
   1004   //
   1005   // Set back to conventional setup resolution
   1006   //
   1007   BdsSetConsoleMode (TRUE);
   1008 
   1009   //
   1010   // Initialize Boot menu data
   1011   //
   1012   Status = InitializeBootMenuData (BootOption, BootOptionCount, &BootMenuData);
   1013   //
   1014   // According to boot menu data to draw boot popup menu
   1015   //
   1016   DrawBootPopupMenu (&BootMenuData);
   1017 
   1018   //
   1019   // check user input to determine want to re-draw or boot from user selected item
   1020   //
   1021   ExitApplication = FALSE;
   1022   while (!ExitApplication) {
   1023     gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &Index);
   1024     Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
   1025     if (!EFI_ERROR (Status)) {
   1026       switch (Key.UnicodeChar) {
   1027 
   1028       case CHAR_NULL:
   1029         switch (Key.ScanCode) {
   1030 
   1031         case SCAN_UP:
   1032           SelectItem = BootMenuData.SelectItem == 0 ? BootMenuData.ItemCount - 1 : BootMenuData.SelectItem - 1;
   1033           BootMenuSelectItem (SelectItem, &BootMenuData);
   1034           break;
   1035 
   1036         case SCAN_DOWN:
   1037           SelectItem = BootMenuData.SelectItem == BootMenuData.ItemCount - 1 ? 0 : BootMenuData.SelectItem + 1;
   1038           BootMenuSelectItem (SelectItem, &BootMenuData);
   1039           break;
   1040 
   1041         case SCAN_ESC:
   1042           gST->ConOut->ClearScreen (gST->ConOut);
   1043           ExitApplication = TRUE;
   1044           //
   1045           // Set boot resolution for normal boot
   1046           //
   1047           BdsSetConsoleMode (FALSE);
   1048           break;
   1049 
   1050         default:
   1051           break;
   1052         }
   1053         break;
   1054 
   1055       case CHAR_CARRIAGE_RETURN:
   1056         gST->ConOut->ClearScreen (gST->ConOut);
   1057         //
   1058         // Set boot resolution for normal boot
   1059         //
   1060         BdsSetConsoleMode (FALSE);
   1061         BootFromSelectOption (BootOption, BootOptionCount, BootMenuData.SelectItem);
   1062         //
   1063         // Back to boot manager menu again, set back to setup resolution
   1064         //
   1065         BdsSetConsoleMode (TRUE);
   1066         DrawBootPopupMenu (&BootMenuData);
   1067         break;
   1068 
   1069       default:
   1070         break;
   1071       }
   1072     }
   1073   }
   1074   EfiBootManagerFreeLoadOptions (BootOption, BootOptionCount);
   1075   FreePool (BootMenuData.PtrTokens);
   1076 
   1077   HiiRemovePackages (gStringPackHandle);
   1078 
   1079   return Status;
   1080 
   1081 }
   1082