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