Home | History | Annotate | Download | only in FrameworkHiiOnUefiHiiThunk
      1 /** @file
      2 Framework to UEFI 2.1 Setup Browser Thunk. The file consume EFI_FORM_BROWSER2_PROTOCOL
      3 to produce a EFI_FORM_BROWSER_PROTOCOL.
      4 
      5 Copyright (c) 2008 - 2011, Intel Corporation. All rights reserved.<BR>
      6 This program and the accompanying materials
      7 are licensed and made available under the terms and conditions of the BSD License
      8 which accompanies this distribution.  The full text of the license may be found at
      9 http://opensource.org/licenses/bsd-license.php
     10 
     11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 #include "HiiDatabase.h"
     17 #include "SetupBrowser.h"
     18 
     19 EFI_HII_HANDLE gStringPackHandle = NULL;
     20 BOOLEAN mFrontPageDisplayed = FALSE;
     21 //
     22 // 106F3545-B788-4cb5-9D2A-CE0CDB208DF5
     23 //
     24 EFI_GUID gEfiHiiThunkProducerGuid = { 0x106f3545, 0xb788, 0x4cb5, { 0x9d, 0x2a, 0xce, 0xc, 0xdb, 0x20, 0x8d, 0xf5 } };
     25 
     26 
     27 /**
     28   Get string by string id from HII Interface
     29 
     30 
     31   @param Id              String ID.
     32 
     33   @retval  CHAR16 *  String from ID.
     34   @retval  NULL      If error occurs.
     35 
     36 **/
     37 CHAR16 *
     38 GetStringById (
     39   IN  EFI_STRING_ID   Id
     40   )
     41 {
     42   return HiiGetString (gStringPackHandle, Id, NULL);
     43 }
     44 
     45 /**
     46 
     47   Show progress bar with title above it. It only works in Graphics mode.
     48 
     49 
     50   @param TitleForeground Foreground color for Title.
     51   @param TitleBackground Background color for Title.
     52   @param Title           Title above progress bar.
     53   @param ProgressColor   Progress bar color.
     54   @param Progress        Progress (0-100)
     55   @param PreviousValue   The previous value of the progress.
     56 
     57   @retval  EFI_STATUS       Success update the progress bar
     58 
     59 **/
     60 EFI_STATUS
     61 PlatformBdsShowProgress (
     62   IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL TitleForeground,
     63   IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL TitleBackground,
     64   IN CHAR16                        *Title,
     65   IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL ProgressColor,
     66   IN UINTN                         Progress,
     67   IN UINTN                         PreviousValue
     68   )
     69 {
     70   EFI_STATUS                     Status;
     71   EFI_GRAPHICS_OUTPUT_PROTOCOL   *GraphicsOutput;
     72   EFI_UGA_DRAW_PROTOCOL          *UgaDraw;
     73   UINT32                         SizeOfX;
     74   UINT32                         SizeOfY;
     75   UINT32                         ColorDepth;
     76   UINT32                         RefreshRate;
     77   EFI_GRAPHICS_OUTPUT_BLT_PIXEL  Color;
     78   UINTN                          BlockHeight;
     79   UINTN                          BlockWidth;
     80   UINTN                          BlockNum;
     81   UINTN                          PosX;
     82   UINTN                          PosY;
     83   UINTN                          Index;
     84 
     85   if (Progress > 100) {
     86     return EFI_INVALID_PARAMETER;
     87   }
     88 
     89   UgaDraw = NULL;
     90   Status = gBS->HandleProtocol (
     91                   gST->ConsoleOutHandle,
     92                   &gEfiGraphicsOutputProtocolGuid,
     93                   (VOID **) &GraphicsOutput
     94                   );
     95   if (EFI_ERROR (Status)) {
     96     GraphicsOutput = NULL;
     97 
     98     Status = gBS->HandleProtocol (
     99                     gST->ConsoleOutHandle,
    100                     &gEfiUgaDrawProtocolGuid,
    101                     (VOID **) &UgaDraw
    102                     );
    103   }
    104   if (EFI_ERROR (Status) || (GraphicsOutput == NULL && UgaDraw == NULL)) {
    105     return EFI_UNSUPPORTED;
    106   }
    107 
    108   SizeOfX = 0;
    109   SizeOfY = 0;
    110   if (GraphicsOutput != NULL) {
    111     SizeOfX = GraphicsOutput->Mode->Info->HorizontalResolution;
    112     SizeOfY = GraphicsOutput->Mode->Info->VerticalResolution;
    113   } else {
    114     Status = UgaDraw->GetMode (
    115                         UgaDraw,
    116                         &SizeOfX,
    117                         &SizeOfY,
    118                         &ColorDepth,
    119                         &RefreshRate
    120                         );
    121     if (EFI_ERROR (Status)) {
    122       return EFI_UNSUPPORTED;
    123     }
    124   }
    125 
    126   BlockWidth  = SizeOfX / 100;
    127   BlockHeight = SizeOfY / 50;
    128 
    129   BlockNum    = Progress;
    130 
    131   PosX        = 0;
    132   PosY        = SizeOfY * 48 / 50;
    133 
    134   if (BlockNum == 0) {
    135     //
    136     // Clear progress area
    137     //
    138     SetMem (&Color, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0x0);
    139 
    140     if (GraphicsOutput != NULL) {
    141       Status = GraphicsOutput->Blt (
    142                           GraphicsOutput,
    143                           &Color,
    144                           EfiBltVideoFill,
    145                           0,
    146                           0,
    147                           0,
    148                           PosY - EFI_GLYPH_HEIGHT - 1,
    149                           SizeOfX,
    150                           SizeOfY - (PosY - EFI_GLYPH_HEIGHT - 1),
    151                           SizeOfX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
    152                           );
    153     } else {
    154       Status = UgaDraw->Blt (
    155                           UgaDraw,
    156                           (EFI_UGA_PIXEL *) &Color,
    157                           EfiUgaVideoFill,
    158                           0,
    159                           0,
    160                           0,
    161                           PosY - EFI_GLYPH_HEIGHT - 1,
    162                           SizeOfX,
    163                           SizeOfY - (PosY - EFI_GLYPH_HEIGHT - 1),
    164                           SizeOfX * sizeof (EFI_UGA_PIXEL)
    165                           );
    166     }
    167   }
    168   //
    169   // Show progress by drawing blocks
    170   //
    171   for (Index = PreviousValue; Index < BlockNum; Index++) {
    172     PosX = Index * BlockWidth;
    173     if (GraphicsOutput != NULL) {
    174       Status = GraphicsOutput->Blt (
    175                           GraphicsOutput,
    176                           &ProgressColor,
    177                           EfiBltVideoFill,
    178                           0,
    179                           0,
    180                           PosX,
    181                           PosY,
    182                           BlockWidth - 1,
    183                           BlockHeight,
    184                           (BlockWidth) * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
    185                           );
    186     } else {
    187       Status = UgaDraw->Blt (
    188                           UgaDraw,
    189                           (EFI_UGA_PIXEL *) &ProgressColor,
    190                           EfiUgaVideoFill,
    191                           0,
    192                           0,
    193                           PosX,
    194                           PosY,
    195                           BlockWidth - 1,
    196                           BlockHeight,
    197                           (BlockWidth) * sizeof (EFI_UGA_PIXEL)
    198                           );
    199     }
    200   }
    201 
    202   PrintXY (
    203     (SizeOfX - StrLen (Title) * EFI_GLYPH_WIDTH) / 2,
    204     PosY - EFI_GLYPH_HEIGHT - 1,
    205     &TitleForeground,
    206     &TitleBackground,
    207     Title
    208     );
    209 
    210   return EFI_SUCCESS;
    211 }
    212 
    213 /**
    214   Function waits for a given event to fire, or for an optional timeout to expire.
    215 
    216 
    217   @param Event           The event to wait for
    218 
    219   @param Timeout         An optional timeout value in 100 ns units.
    220 
    221   @retval  EFI_SUCCESS       Event fired before Timeout expired.
    222   @retval  EFI_TIME_OUT      Timout expired before Event fired..
    223 
    224 **/
    225 EFI_STATUS
    226 WaitForSingleEvent (
    227   IN EFI_EVENT                  Event,
    228   IN UINT64                     Timeout OPTIONAL
    229   )
    230 {
    231   EFI_STATUS  Status;
    232   UINTN       Index;
    233   EFI_EVENT   TimerEvent;
    234   EFI_EVENT   WaitList[2];
    235 
    236   if (Timeout != 0) {
    237     //
    238     // Create a timer event
    239     //
    240     Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent);
    241     if (!EFI_ERROR (Status)) {
    242       //
    243       // Set the timer event
    244       //
    245       gBS->SetTimer (
    246             TimerEvent,
    247             TimerRelative,
    248             Timeout
    249             );
    250 
    251       //
    252       // Wait for the original event or the timer
    253       //
    254       WaitList[0] = Event;
    255       WaitList[1] = TimerEvent;
    256       Status      = gBS->WaitForEvent (2, WaitList, &Index);
    257       gBS->CloseEvent (TimerEvent);
    258 
    259       //
    260       // If the timer expired, change the return to timed out
    261       //
    262       if (!EFI_ERROR (Status) && Index == 1) {
    263         Status = EFI_TIMEOUT;
    264       }
    265     }
    266   } else {
    267     //
    268     // No timeout... just wait on the event
    269     //
    270     Status = gBS->WaitForEvent (1, &Event, &Index);
    271     ASSERT (!EFI_ERROR (Status));
    272     ASSERT (Index == 0);
    273   }
    274 
    275   return Status;
    276 }
    277 
    278 /**
    279   Function show progress bar to wait for user input.
    280 
    281 
    282   @param TimeoutDefault  - The fault time out value before the system
    283                          continue to boot.
    284 
    285   @retval  EFI_SUCCESS       User pressed some key except "Enter"
    286   @retval  EFI_TIME_OUT      Timout expired or user press "Enter"
    287 
    288 **/
    289 EFI_STATUS
    290 ShowProgress (
    291   IN UINT16                       TimeoutDefault
    292   )
    293 {
    294   EFI_STATUS                    Status;
    295   CHAR16                        *TmpStr;
    296   EFI_GRAPHICS_OUTPUT_BLT_PIXEL Foreground;
    297   EFI_GRAPHICS_OUTPUT_BLT_PIXEL Background;
    298   EFI_GRAPHICS_OUTPUT_BLT_PIXEL Color;
    299   EFI_INPUT_KEY                 Key;
    300   UINT16                        TimeoutRemain;
    301 
    302   if (TimeoutDefault == 0) {
    303     return EFI_TIMEOUT;
    304   }
    305 
    306   DEBUG ((EFI_D_INFO, "\n\nStart showing progress bar... Press any key to stop it! ...Zzz....\n"));
    307 
    308   SetMem (&Foreground, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0xff);
    309   SetMem (&Background, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0x0);
    310   SetMem (&Color, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0xff);
    311 
    312   //
    313   // Clear the progress status bar first
    314   //
    315   TmpStr = GetStringById (STRING_TOKEN (STR_START_BOOT_OPTION));
    316   if (TmpStr != NULL) {
    317     PlatformBdsShowProgress (Foreground, Background, TmpStr, Color, 0, 0);
    318   }
    319 
    320   TimeoutRemain = TimeoutDefault;
    321   while (TimeoutRemain != 0) {
    322     DEBUG ((EFI_D_INFO, "Showing progress bar...Remaining %d second!\n", TimeoutRemain));
    323 
    324     Status = WaitForSingleEvent (gST->ConIn->WaitForKey, ONE_SECOND);
    325     if (Status != EFI_TIMEOUT) {
    326       break;
    327     }
    328     TimeoutRemain--;
    329 
    330     //
    331     // Show progress
    332     //
    333     if (TmpStr != NULL) {
    334       PlatformBdsShowProgress (
    335         Foreground,
    336         Background,
    337         TmpStr,
    338         Color,
    339         ((TimeoutDefault - TimeoutRemain) * 100 / TimeoutDefault),
    340         0
    341         );
    342     }
    343   }
    344   gBS->FreePool (TmpStr);
    345 
    346   //
    347   // Timeout expired
    348   //
    349   if (TimeoutRemain == 0) {
    350     return EFI_TIMEOUT;
    351   }
    352 
    353   //
    354   // User pressed some key
    355   //
    356   Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
    357   if (EFI_ERROR (Status)) {
    358     return Status;
    359   }
    360 
    361   if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
    362     //
    363     // User pressed enter, equivalent to select "continue"
    364     //
    365     return EFI_TIMEOUT;
    366   }
    367 
    368   return EFI_SUCCESS;
    369 }
    370 
    371 /**
    372   Return the default value for system Timeout variable.
    373 
    374   @return Timeout value.
    375 
    376 **/
    377 UINT16
    378 EFIAPI
    379 GetTimeout (
    380   VOID
    381   )
    382 {
    383   return PcdGet16 (PcdPlatformBootTimeOut);
    384 }
    385 
    386 
    387 /**
    388   This is the Framework Setup Browser interface which displays a FormSet.
    389 
    390   @param This           The EFI_FORM_BROWSER_PROTOCOL context.
    391   @param UseDatabase    TRUE if the FormSet is from HII database. The Thunk implementation
    392                         only support UseDatabase is TRUE.
    393   @param Handle         The Handle buffer.
    394   @param HandleCount    The number of Handle in the Handle Buffer. It must be 1 for this implementation.
    395   @param Packet         The pointer to data buffer containing IFR and String package. Not supported.
    396   @param CallbackHandle Not supported.
    397   @param NvMapOverride  The buffer is used only when there is no NV variable to define the
    398                         current settings and the caller needs to provide to the browser the
    399                         current settings for the the "fake" NV variable. If used, no saving of
    400                         an NV variable is possbile. This parameter is also ignored if Handle is NULL.
    401   @param ScreenDimensions
    402                         Allows the browser to be called so that it occupies a portion of the physical
    403                         screen instead of dynamically determining the screen dimensions.
    404   @param ResetRequired  This BOOLEAN value denotes whether a reset is required based on the data that
    405                         might have been changed. The ResetRequired parameter is primarily applicable
    406                         for configuration applications, and is an optional parameter.
    407 
    408   @retval EFI_SUCCESS             If the Formset is displayed correctly.
    409   @retval EFI_UNSUPPORTED         If UseDatabase is FALSE or HandleCount is not 1.
    410   @retval EFI_INVALID_PARAMETER   If the *Handle passed in is not found in the database.
    411 **/
    412 EFI_STATUS
    413 EFIAPI
    414 ThunkSendForm (
    415   IN  EFI_FORM_BROWSER_PROTOCOL         *This,
    416   IN  BOOLEAN                           UseDatabase,
    417   IN  FRAMEWORK_EFI_HII_HANDLE          *Handle,
    418   IN  UINTN                             HandleCount,
    419   IN  EFI_IFR_PACKET                    *Packet, OPTIONAL
    420   IN  EFI_HANDLE                        CallbackHandle, OPTIONAL
    421   IN  UINT8                             *NvMapOverride, OPTIONAL
    422   IN  FRAMEWORK_EFI_SCREEN_DESCRIPTOR   *ScreenDimensions, OPTIONAL
    423   OUT BOOLEAN                           *ResetRequired OPTIONAL
    424   )
    425 {
    426   EFI_STATUS                        Status;
    427   EFI_BROWSER_ACTION_REQUEST        ActionRequest;
    428   HII_THUNK_CONTEXT                 *ThunkContext;
    429   HII_THUNK_PRIVATE_DATA            *Private;
    430   EFI_FORMBROWSER_THUNK_PRIVATE_DATA *BrowserPrivate;
    431 
    432   if (!UseDatabase) {
    433     //
    434     // ThunkSendForm only support displays forms registered into the HII database.
    435     //
    436     return EFI_UNSUPPORTED;
    437   }
    438 
    439   if (HandleCount != 1 ) {
    440     return EFI_UNSUPPORTED;
    441   }
    442 
    443   BrowserPrivate = EFI_FORMBROWSER_THUNK_PRIVATE_DATA_FROM_THIS (This);
    444   Private = BrowserPrivate->ThunkPrivate;
    445 
    446   ThunkContext = FwHiiHandleToThunkContext (Private, *Handle);
    447   if (ThunkContext == NULL) {
    448     return EFI_INVALID_PARAMETER;
    449   }
    450 
    451   //
    452   // Following UEFI spec to do auto booting after a time-out. This feature is implemented
    453   // in Framework Setup Browser and moved to MdeModulePkg/Universal/BdsDxe. The auto booting is
    454   // moved here in HII Thunk module.
    455   //
    456   if (CompareGuid (&gFrameworkBdsFrontPageFormsetGuid, &ThunkContext->FormSet->Guid) && !mFrontPageDisplayed) {
    457     //
    458     // Send form is called before entering the
    459     //
    460     mFrontPageDisplayed = TRUE;
    461     Status = ShowProgress (GetTimeout ());
    462 
    463     if (EFI_ERROR (Status)) {
    464       return Status;
    465     }
    466   }
    467 
    468   if (NvMapOverride != NULL) {
    469     ThunkContext->NvMapOverride = NvMapOverride;
    470   }
    471 
    472   Status = mFormBrowser2Protocol->SendForm (
    473                                     mFormBrowser2Protocol,
    474                                     &ThunkContext->UefiHiiHandle,
    475                                     1,
    476                                     NULL,
    477                                     0,
    478                                     (EFI_SCREEN_DESCRIPTOR *) ScreenDimensions,
    479                                     &ActionRequest
    480                                     );
    481 
    482   if (ActionRequest == EFI_BROWSER_ACTION_REQUEST_RESET) {
    483     *ResetRequired = TRUE;
    484   }
    485 
    486   return Status;
    487 }
    488 
    489 /**
    490 
    491   Rountine used to display a generic dialog interface and return
    492   the Key or Input from user input.
    493 
    494   @param LinesNumber   The number of lines for the dialog box.
    495   @param HotKey        Defines if a single character is parsed (TRUE) and returned in KeyValue
    496                        or if a string is returned in StringBuffer.
    497   @param MaximumStringSize The maximum size in bytes of a typed-in string.
    498   @param StringBuffer  On return contains the typed-in string if HotKey is FALSE.
    499   @param Key           The EFI_INPUT_KEY value returned if HotKey is TRUE.
    500   @param FirstString   The pointer to the first string in the list of strings
    501                        that comprise the dialog box.
    502   @param ...           A series of NumberOfLines text strings that will be used
    503                        to construct the dialog box.
    504   @retval EFI_SUCCESS  The dialog is created successfully and user interaction was received.
    505   @retval EFI_DEVICE_ERROR The user typed in an ESC.
    506   @retval EFI_INVALID_PARAMETER One of the parameters was invalid.(StringBuffer == NULL && HotKey == FALSE).
    507 **/
    508 EFI_STATUS
    509 EFIAPI
    510 ThunkCreatePopUp (
    511   IN  UINTN                           LinesNumber,
    512   IN  BOOLEAN                         HotKey,
    513   IN  UINTN                           MaximumStringSize,
    514   OUT CHAR16                          *StringBuffer,
    515   OUT EFI_INPUT_KEY                   *Key,
    516   IN  CHAR16                          *FirstString,
    517   ...
    518   )
    519 {
    520   VA_LIST                          Args;
    521   EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *ConOut;
    522   EFI_SIMPLE_TEXT_OUTPUT_MODE      SavedConsoleMode;
    523   UINTN                            Columns;
    524   UINTN                            Rows;
    525   UINTN                            Column;
    526   UINTN                            Row;
    527   UINTN                            NumberOfLines;
    528   UINTN                            MaxLength;
    529   CHAR16                           *String;
    530   UINTN                            Length;
    531   CHAR16                           *Line;
    532   UINTN                            EventIndex;
    533 
    534   if (!HotKey) {
    535     return EFI_UNSUPPORTED;
    536   }
    537 
    538   if (MaximumStringSize == 0) {
    539     //
    540     // Blank strint to output
    541     //
    542     return EFI_INVALID_PARAMETER;
    543   }
    544 
    545   //
    546   // Determine the length of the longest line in the popup and the the total
    547   // number of lines in the popup
    548   //
    549   MaxLength = StrLen (FirstString);
    550   NumberOfLines = 1;
    551   VA_START (Args, FirstString);
    552   while ((String = VA_ARG (Args, CHAR16 *)) != NULL) {
    553     MaxLength = MAX (MaxLength, StrLen (String));
    554     NumberOfLines++;
    555   }
    556   VA_END (Args);
    557 
    558   //
    559   // If the total number of lines in the popup is not same to the input NumberOfLines
    560   // the parameter is not valid. Not check.
    561   //
    562   //  if (NumberOfLines != LinesNumber) {
    563   //    return EFI_INVALID_PARAMETER;
    564   //  }
    565 
    566   //
    567   // If the maximum length of all the strings is not same to the input MaximumStringSize
    568   // the parameter is not valid. Not check.
    569   //
    570   // if (MaxLength != MaximumStringSize) {
    571   //   return EFI_INVALID_PARAMETER;
    572   // }
    573 
    574   //
    575   // Cache a pointer to the Simple Text Output Protocol in the EFI System Table
    576   //
    577   ConOut = gST->ConOut;
    578 
    579   //
    580   // Save the current console cursor position and attributes
    581   //
    582   CopyMem (&SavedConsoleMode, ConOut->Mode, sizeof (SavedConsoleMode));
    583 
    584   //
    585   // Retrieve the number of columns and rows in the current console mode
    586   //
    587   ConOut->QueryMode (ConOut, SavedConsoleMode.Mode, &Columns, &Rows);
    588 
    589   //
    590   // Disable cursor and set the foreground and background colors specified by Attribute
    591   //
    592   ConOut->EnableCursor (ConOut, FALSE);
    593   ConOut->SetAttribute (ConOut, EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE);
    594 
    595   //
    596   // Limit NumberOfLines to height of the screen minus 3 rows for the box itself
    597   //
    598   NumberOfLines = MIN (NumberOfLines, Rows - 3);
    599 
    600   //
    601   // Limit MaxLength to width of the screen minus 2 columns for the box itself
    602   //
    603   MaxLength = MIN (MaxLength, Columns - 2);
    604 
    605   //
    606   // Compute the starting row and starting column for the popup
    607   //
    608   Row    = (Rows - (NumberOfLines + 3)) / 2;
    609   Column = (Columns - (MaxLength + 2)) / 2;
    610 
    611   //
    612   // Allocate a buffer for a single line of the popup with borders and a Null-terminator
    613   //
    614   Line = AllocateZeroPool ((MaxLength + 3) * sizeof (CHAR16));
    615   ASSERT (Line != NULL);
    616 
    617   //
    618   // Draw top of popup box
    619   //
    620   SetMem16 (Line, (MaxLength + 2) * 2, BOXDRAW_HORIZONTAL);
    621   Line[0]             = BOXDRAW_DOWN_RIGHT;
    622   Line[MaxLength + 1] = BOXDRAW_DOWN_LEFT;
    623   Line[MaxLength + 2] = L'\0';
    624   ConOut->SetCursorPosition (ConOut, Column, Row++);
    625   ConOut->OutputString (ConOut, Line);
    626 
    627   //
    628   // Draw middle of the popup with strings
    629   //
    630   VA_START (Args, FirstString);
    631   String = FirstString;
    632   while ((String != NULL) && (NumberOfLines > 0)) {
    633     Length = StrLen (String);
    634     SetMem16 (Line, (MaxLength + 2) * 2, L' ');
    635     if (Length <= MaxLength) {
    636       //
    637       // Length <= MaxLength
    638       //
    639       CopyMem (Line + 1 + (MaxLength - Length) / 2, String , Length * sizeof (CHAR16));
    640     } else {
    641       //
    642       // Length > MaxLength
    643       //
    644       CopyMem (Line + 1, String + (Length - MaxLength) / 2 , MaxLength * sizeof (CHAR16));
    645     }
    646     Line[0]             = BOXDRAW_VERTICAL;
    647     Line[MaxLength + 1] = BOXDRAW_VERTICAL;
    648     Line[MaxLength + 2] = L'\0';
    649     ConOut->SetCursorPosition (ConOut, Column, Row++);
    650     ConOut->OutputString (ConOut, Line);
    651     String = VA_ARG (Args, CHAR16 *);
    652     NumberOfLines--;
    653   }
    654   VA_END (Args);
    655 
    656   //
    657   // Draw bottom of popup box
    658   //
    659   SetMem16 (Line, (MaxLength + 2) * 2, BOXDRAW_HORIZONTAL);
    660   Line[0]             = BOXDRAW_UP_RIGHT;
    661   Line[MaxLength + 1] = BOXDRAW_UP_LEFT;
    662   Line[MaxLength + 2] = L'\0';
    663   ConOut->SetCursorPosition (ConOut, Column, Row++);
    664   ConOut->OutputString (ConOut, Line);
    665 
    666   //
    667   // Free the allocated line buffer
    668   //
    669   FreePool (Line);
    670 
    671   //
    672   // Restore the cursor visibility, position, and attributes
    673   //
    674   ConOut->EnableCursor      (ConOut, SavedConsoleMode.CursorVisible);
    675   ConOut->SetCursorPosition (ConOut, SavedConsoleMode.CursorColumn, SavedConsoleMode.CursorRow);
    676   ConOut->SetAttribute      (ConOut, SavedConsoleMode.Attribute);
    677 
    678   //
    679   // Wait for a keystroke
    680   //
    681   if (Key != NULL) {
    682     gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex);
    683     gST->ConIn->ReadKeyStroke (gST->ConIn, Key);
    684   }
    685 
    686   return EFI_SUCCESS;
    687 }
    688 
    689 /**
    690 
    691   Initialize string packages in HII database.
    692 
    693 **/
    694 VOID
    695 InitSetBrowserStrings (
    696   VOID
    697   )
    698 {
    699   //
    700   // Initialize strings to HII database
    701   //
    702   gStringPackHandle = HiiAddPackages (
    703                         &gEfiHiiThunkProducerGuid,
    704                         NULL,
    705                         STRING_ARRAY_NAME,
    706                         NULL
    707                         );
    708   ASSERT (gStringPackHandle != NULL);
    709 }
    710