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