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 *
GetStringById(IN EFI_STRING_ID Id)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
PlatformBdsShowProgress(IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL TitleForeground,IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL TitleBackground,IN CHAR16 * Title,IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL ProgressColor,IN UINTN Progress,IN UINTN PreviousValue)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
WaitForSingleEvent(IN EFI_EVENT Event,IN UINT64 Timeout OPTIONAL)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
ShowProgress(IN UINT16 TimeoutDefault)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
GetTimeout(VOID)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
ThunkSendForm(IN EFI_FORM_BROWSER_PROTOCOL * This,IN BOOLEAN UseDatabase,IN FRAMEWORK_EFI_HII_HANDLE * Handle,IN UINTN HandleCount,IN EFI_IFR_PACKET * Packet,OPTIONAL IN EFI_HANDLE CallbackHandle,OPTIONAL IN UINT8 * NvMapOverride,OPTIONAL IN FRAMEWORK_EFI_SCREEN_DESCRIPTOR * ScreenDimensions,OPTIONAL OUT BOOLEAN * ResetRequired OPTIONAL)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
ThunkCreatePopUp(IN UINTN LinesNumber,IN BOOLEAN HotKey,IN UINTN MaximumStringSize,OUT CHAR16 * StringBuffer,OUT EFI_INPUT_KEY * Key,IN CHAR16 * FirstString,...)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
InitSetBrowserStrings(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