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