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