• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
PrintStringAt(IN UINTN Column,IN UINTN Row,IN CHAR16 * String)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
PrintCharAt(IN UINTN Column,IN UINTN Row,CHAR16 Character)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
GetLineWidth(IN EFI_STRING_ID StringId)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
InitializeBootMenuScreen(IN OUT BOOT_MENU_POPUP_DATA * BootMenuData)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
IsBootManagerMenu(IN EFI_BOOT_MANAGER_LOAD_OPTION * BootOption)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
IgnoreBootOption(IN EFI_BOOT_MANAGER_LOAD_OPTION * BootOption)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
InitializeBootMenuData(IN EFI_BOOT_MANAGER_LOAD_OPTION * BootOption,IN UINTN BootOptionCount,OUT BOOT_MENU_POPUP_DATA * BootMenuData)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
BootMenuSelectItem(IN UINTN WantSelectItem,IN OUT BOOT_MENU_POPUP_DATA * BootMenuData)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
DrawBootPopupMenu(IN BOOT_MENU_POPUP_DATA * BootMenuData)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
BootFromSelectOption(IN EFI_BOOT_MANAGER_LOAD_OPTION * BootOptions,IN UINTN BootOptionCount,IN UINTN SelectItem)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
BdsSetConsoleMode(BOOLEAN IsSetupMode)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
BootManagerMenuEntry(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)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