]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenu.c
be1341061e60ca8604c338ad1ab6dd80428d889c
[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 Return whether to ignore the boot option.
248
249 @param BootOption Pointer to EFI_BOOT_MANAGER_LOAD_OPTION to check.
250
251 @retval TRUE Ignore the boot optin.
252 @retval FALSE Do not ignore the boot option.
253 **/
254 BOOLEAN
255 IgnoreBootOption (
256 IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOption
257 )
258 {
259 EFI_STATUS Status;
260 EFI_DEVICE_PATH_PROTOCOL *ImageDevicePath;
261
262 //
263 // Ignore myself.
264 //
265 Status = gBS->HandleProtocol (gImageHandle, &gEfiLoadedImageDevicePathProtocolGuid, (VOID **) &ImageDevicePath);
266 ASSERT_EFI_ERROR (Status);
267 if (CompareMem (BootOption->FilePath, ImageDevicePath, GetDevicePathSize (ImageDevicePath)) == 0) {
268 return TRUE;
269 }
270
271 //
272 // Do not ignore Boot Manager Menu.
273 //
274 if (IsBootManagerMenu (BootOption)) {
275 return FALSE;
276 }
277
278 //
279 // Ignore the hidden/inactive boot option.
280 //
281 if (((BootOption->Attributes & LOAD_OPTION_HIDDEN) != 0) || ((BootOption->Attributes & LOAD_OPTION_ACTIVE) == 0)) {
282 return TRUE;
283 }
284
285 return FALSE;
286 }
287
288 /**
289 This funciton uses to initialize boot menu data
290
291 @param BootOption Pointer to EFI_BOOT_MANAGER_LOAD_OPTION array.
292 @param BootOptionCount Number of boot option.
293 @param BootMenuData The Input BootMenuData to be initialized.
294
295 @retval EFI_SUCCESS Initialize boot menu data successful.
296 @retval EFI_INVALID_PARAMETER Input parameter is invalid.
297
298 **/
299 EFI_STATUS
300 InitializeBootMenuData (
301 IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOption,
302 IN UINTN BootOptionCount,
303 OUT BOOT_MENU_POPUP_DATA *BootMenuData
304 )
305 {
306 UINTN Index;
307 UINTN StrIndex;
308
309 if (BootOption == NULL || BootMenuData == NULL) {
310 return EFI_INVALID_PARAMETER;
311 }
312
313 BootMenuData->TitleToken[0] = STRING_TOKEN (STR_BOOT_POPUP_MENU_TITLE_STRING);
314 BootMenuData->PtrTokens = AllocateZeroPool (BootOptionCount * sizeof (EFI_STRING_ID));
315 ASSERT (BootMenuData->PtrTokens != NULL);
316
317 //
318 // Skip boot option which created by BootNext Variable
319 //
320 for (StrIndex = 0, Index = 0; Index < BootOptionCount; Index++) {
321 if (IgnoreBootOption (&BootOption[Index])) {
322 continue;
323 }
324
325 ASSERT (BootOption[Index].Description != NULL);
326 BootMenuData->PtrTokens[StrIndex++] = HiiSetString (
327 gStringPackHandle,
328 0,
329 BootOption[Index].Description,
330 NULL
331 );
332 }
333
334 BootMenuData->ItemCount = StrIndex;
335 BootMenuData->HelpToken[0] = STRING_TOKEN (STR_BOOT_POPUP_MENU_HELP1_STRING);
336 BootMenuData->HelpToken[1] = STRING_TOKEN (STR_BOOT_POPUP_MENU_HELP2_STRING);
337 BootMenuData->HelpToken[2] = STRING_TOKEN (STR_BOOT_POPUP_MENU_HELP3_STRING);
338 InitializeBootMenuScreen (BootMenuData);
339 BootMenuData->SelectItem = 0;
340 return EFI_SUCCESS;
341 }
342
343 /**
344 This function uses input select item to highlight selected item
345 and set current selected item in BootMenuData
346
347 @param WantSelectItem The user wants to select item.
348 @param BootMenuData The boot menu data to be proccessed
349
350 @return EFI_SUCCESS Highlight selected item and update current selected
351 item successful
352 @retval EFI_INVALID_PARAMETER Input parameter is invalid
353 **/
354 EFI_STATUS
355 BootMenuSelectItem (
356 IN UINTN WantSelectItem,
357 IN OUT BOOT_MENU_POPUP_DATA *BootMenuData
358 )
359 {
360 INT32 SavedAttribute;
361 EFI_STRING String;
362 UINTN StartCol;
363 UINTN StartRow;
364 UINTN PrintCol;
365 UINTN PrintRow;
366 UINTN TopShadeNum;
367 UINTN LowShadeNum;
368 UINTN FirstItem;
369 UINTN LastItem;
370 UINTN ItemCountPerScreen;
371 UINTN Index;
372 BOOLEAN RePaintItems;
373
374 if (BootMenuData == NULL || WantSelectItem >= BootMenuData->ItemCount) {
375 return EFI_INVALID_PARAMETER;
376 }
377 SavedAttribute = gST->ConOut->Mode->Attribute;
378 RePaintItems = FALSE;
379 StartCol = BootMenuData->MenuScreen.StartCol;
380 StartRow = BootMenuData->MenuScreen.StartRow;
381 //
382 // print selectable items again and adjust scroll bar if need
383 //
384 if (BootMenuData->ScrollBarControl.HasScrollBar &&
385 (WantSelectItem < BootMenuData->ScrollBarControl.FirstItem ||
386 WantSelectItem > BootMenuData->ScrollBarControl.LastItem ||
387 WantSelectItem == BootMenuData->SelectItem)) {
388 ItemCountPerScreen = BootMenuData->ScrollBarControl.ItemCountPerScreen;
389 //
390 // Set first item and last item
391 //
392 if (WantSelectItem < BootMenuData->ScrollBarControl.FirstItem) {
393 BootMenuData->ScrollBarControl.FirstItem = WantSelectItem;
394 BootMenuData->ScrollBarControl.LastItem = WantSelectItem + ItemCountPerScreen - 1;
395 } else if (WantSelectItem > BootMenuData->ScrollBarControl.LastItem) {
396 BootMenuData->ScrollBarControl.FirstItem = WantSelectItem - ItemCountPerScreen + 1;
397 BootMenuData->ScrollBarControl.LastItem = WantSelectItem;
398 }
399 gST->ConOut->SetAttribute (gST->ConOut, EFI_WHITE | EFI_BACKGROUND_BLUE);
400 FirstItem = BootMenuData->ScrollBarControl.FirstItem;
401 LastItem = BootMenuData->ScrollBarControl.LastItem;
402 TopShadeNum = 0;
403 if (FirstItem != 0) {
404 TopShadeNum = (FirstItem * ItemCountPerScreen) / BootMenuData->ItemCount;
405 if ((FirstItem * ItemCountPerScreen) % BootMenuData->ItemCount != 0) {
406 TopShadeNum++;
407 }
408 PrintCol = StartCol + BootMenuData->MenuScreen.Width - 2;
409 PrintRow = StartRow + TITLE_TOKEN_COUNT + 2;
410 for (Index = 0; Index < TopShadeNum; Index++, PrintRow++) {
411 PrintCharAt (PrintCol, PrintRow, BLOCKELEMENT_LIGHT_SHADE);
412 }
413 }
414 LowShadeNum = 0;
415 if (LastItem != BootMenuData->ItemCount - 1) {
416 LowShadeNum = ((BootMenuData->ItemCount - 1 - LastItem) * ItemCountPerScreen) / BootMenuData->ItemCount;
417 if (((BootMenuData->ItemCount - 1 - LastItem) * ItemCountPerScreen) % BootMenuData->ItemCount != 0) {
418 LowShadeNum++;
419 }
420 PrintCol = StartCol + BootMenuData->MenuScreen.Width - 2;
421 PrintRow = StartRow + TITLE_TOKEN_COUNT + 2 + ItemCountPerScreen - LowShadeNum;
422 for (Index = 0; Index < LowShadeNum; Index++, PrintRow++) {
423 PrintCharAt (PrintCol, PrintRow, BLOCKELEMENT_LIGHT_SHADE);
424 }
425 }
426 PrintCol = StartCol + BootMenuData->MenuScreen.Width - 2;
427 PrintRow = StartRow + TITLE_TOKEN_COUNT + 2 + TopShadeNum;
428 for (Index = TopShadeNum; Index < ItemCountPerScreen - LowShadeNum; Index++, PrintRow++) {
429 PrintCharAt (PrintCol, PrintRow, BLOCKELEMENT_FULL_BLOCK);
430 }
431
432
433 //
434 // Clear selectable items first
435 //
436 PrintCol = StartCol + 1;
437 PrintRow = StartRow + TITLE_TOKEN_COUNT + 2;
438 String = AllocateZeroPool ((BootMenuData->MenuScreen.Width - 2) * sizeof (CHAR16));
439 ASSERT (String != NULL);
440 for (Index = 0; Index < BootMenuData->MenuScreen.Width - 3; Index++) {
441 String[Index] = 0x20;
442 }
443 for (Index = 0; Index < ItemCountPerScreen; Index++) {
444 PrintStringAt (PrintCol, PrintRow + Index, String);
445 }
446 FreePool (String);
447 //
448 // print selectable items
449 //
450 for (Index = 0; Index < ItemCountPerScreen; Index++, PrintRow++) {
451 String = HiiGetString (gStringPackHandle, BootMenuData->PtrTokens[Index + FirstItem], NULL);
452 PrintStringAt (PrintCol, PrintRow, String);
453 FreePool (String);
454 }
455 RePaintItems = TRUE;
456 }
457
458 //
459 // Print want to select item
460 //
461 FirstItem = BootMenuData->ScrollBarControl.FirstItem;
462 gST->ConOut->SetAttribute (gST->ConOut, EFI_WHITE | EFI_BACKGROUND_BLACK);
463 String = HiiGetString (gStringPackHandle, BootMenuData->PtrTokens[WantSelectItem], NULL);
464 PrintCol = StartCol + 1;
465 PrintRow = StartRow + TITLE_TOKEN_COUNT + 2 + WantSelectItem - FirstItem;
466 PrintStringAt (PrintCol, PrintRow, String);
467 FreePool (String);
468
469 //
470 // if Want Select and selected item isn't the same and doesn't re-draw selectable
471 // items, clear select item
472 //
473 if (WantSelectItem != BootMenuData->SelectItem && !RePaintItems) {
474 gST->ConOut->SetAttribute (gST->ConOut, EFI_WHITE | EFI_BACKGROUND_BLUE);
475 String = HiiGetString (gStringPackHandle, BootMenuData->PtrTokens[BootMenuData->SelectItem], NULL);
476 PrintCol = StartCol + 1;
477 PrintRow = StartRow + 3 + BootMenuData->SelectItem - FirstItem;
478 PrintStringAt (PrintCol, PrintRow, String);
479 FreePool (String);
480 }
481
482 gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute);
483 BootMenuData->SelectItem = WantSelectItem;
484 return EFI_SUCCESS;
485 }
486
487 /**
488 This funciton uses to draw boot popup menu
489
490 @param BootMenuData The Input BootMenuData to be processed.
491
492 @retval EFI_SUCCESS Draw boot popup menu successful.
493
494 **/
495 EFI_STATUS
496 DrawBootPopupMenu (
497 IN BOOT_MENU_POPUP_DATA *BootMenuData
498 )
499 {
500 EFI_STRING String;
501 UINTN Index;
502 UINTN Width;
503 UINTN StartCol;
504 UINTN StartRow;
505 UINTN PrintRow;
506 UINTN PrintCol;
507 UINTN LineWidth;
508 INT32 SavedAttribute;
509 UINTN ItemCountPerScreen;
510
511 gST->ConOut->ClearScreen (gST->ConOut);
512
513 SavedAttribute = gST->ConOut->Mode->Attribute;
514 gST->ConOut->SetAttribute (gST->ConOut, EFI_WHITE | EFI_BACKGROUND_BLUE);
515 Width = BootMenuData->MenuScreen.Width;
516 StartCol = BootMenuData->MenuScreen.StartCol;
517 StartRow = BootMenuData->MenuScreen.StartRow;
518 ItemCountPerScreen = BootMenuData->ScrollBarControl.ItemCountPerScreen;
519 PrintRow = StartRow;
520
521 gST->ConOut->EnableCursor (gST->ConOut, FALSE);
522 //
523 // Draw Boot popup menu screen
524 //
525 PrintCharAt (StartCol, PrintRow, BOXDRAW_DOWN_RIGHT);
526 for (Index = 1; Index < Width - 1; Index++) {
527 PrintCharAt (StartCol + Index, PrintRow, BOXDRAW_HORIZONTAL);
528 }
529 PrintCharAt (StartCol + Width - 1, PrintRow, BOXDRAW_DOWN_LEFT);
530
531 //
532 // Draw the screen for title
533 //
534 String = AllocateZeroPool ((Width - 1) * sizeof (CHAR16));
535 ASSERT (String != NULL);
536 for (Index = 0; Index < Width - 2; Index++) {
537 String[Index] = 0x20;
538 }
539
540 for (Index = 0; Index < TITLE_TOKEN_COUNT; Index++) {
541 PrintRow++;
542 PrintCharAt (StartCol, PrintRow, BOXDRAW_VERTICAL);
543 PrintStringAt (StartCol + 1, PrintRow, String);
544 PrintCharAt (StartCol + Width - 1, PrintRow, BOXDRAW_VERTICAL);
545 }
546
547 PrintRow++;
548 PrintCharAt (StartCol, PrintRow, BOXDRAW_VERTICAL_RIGHT);
549 for (Index = 1; Index < Width - 1; Index++) {
550 PrintCharAt (StartCol + Index, PrintRow, BOXDRAW_HORIZONTAL);
551 }
552 PrintCharAt (StartCol + Width - 1, PrintRow, BOXDRAW_VERTICAL_LEFT);
553
554 //
555 // Draw screen for selectable items
556 //
557 for (Index = 0; Index < ItemCountPerScreen; Index++) {
558 PrintRow++;
559 PrintCharAt (StartCol, PrintRow, BOXDRAW_VERTICAL);
560 PrintStringAt (StartCol + 1, PrintRow, String);
561 PrintCharAt (StartCol + Width - 1, PrintRow, BOXDRAW_VERTICAL);
562 }
563
564 PrintRow++;
565 PrintCharAt (StartCol, PrintRow, BOXDRAW_VERTICAL_RIGHT);
566 for (Index = 1; Index < Width - 1; Index++) {
567 PrintCharAt (StartCol + Index, PrintRow, BOXDRAW_HORIZONTAL);
568 }
569 PrintCharAt (StartCol + Width - 1, PrintRow, BOXDRAW_VERTICAL_LEFT);
570
571 //
572 // Draw screen for Help
573 //
574 for (Index = 0; Index < HELP_TOKEN_COUNT; Index++) {
575 PrintRow++;
576 PrintCharAt (StartCol, PrintRow, BOXDRAW_VERTICAL);
577 PrintStringAt (StartCol + 1, PrintRow, String);
578 PrintCharAt (StartCol + Width - 1, PrintRow, BOXDRAW_VERTICAL);
579 }
580 FreePool (String);
581
582 PrintRow++;
583 PrintCharAt (StartCol, PrintRow, BOXDRAW_UP_RIGHT);
584 for (Index = 1; Index < Width - 1; Index++) {
585 PrintCharAt (StartCol + Index, PrintRow, BOXDRAW_HORIZONTAL);
586 }
587 PrintCharAt (StartCol + Width - 1, PrintRow, BOXDRAW_UP_LEFT);
588
589
590 //
591 // print title strings
592 //
593 PrintRow = StartRow + 1;
594 for (Index = 0; Index < TITLE_TOKEN_COUNT; Index++, PrintRow++) {
595 String = HiiGetString (gStringPackHandle, BootMenuData->TitleToken[Index], NULL);
596 LineWidth = GetLineWidth (BootMenuData->TitleToken[Index]);
597 PrintCol = StartCol + (Width - LineWidth) / 2;
598 PrintStringAt (PrintCol, PrintRow, String);
599 FreePool (String);
600 }
601
602 //
603 // print selectable items
604 //
605 PrintCol = StartCol + 1;
606 PrintRow = StartRow + TITLE_TOKEN_COUNT + 2;
607 for (Index = 0; Index < ItemCountPerScreen; Index++, PrintRow++) {
608 String = HiiGetString (gStringPackHandle, BootMenuData->PtrTokens[Index], NULL);
609 PrintStringAt (PrintCol, PrintRow, String);
610 FreePool (String);
611 }
612
613 //
614 // Print Help strings
615 //
616 PrintRow++;
617 for (Index = 0; Index < HELP_TOKEN_COUNT; Index++, PrintRow++) {
618 String = HiiGetString (gStringPackHandle, BootMenuData->HelpToken[Index], NULL);
619 LineWidth = GetLineWidth (BootMenuData->HelpToken[Index]);
620 PrintCol = StartCol + (Width - LineWidth) / 2;
621 PrintStringAt (PrintCol, PrintRow, String);
622 FreePool (String);
623 }
624
625 //
626 // Print scroll bar if has scroll bar
627 //
628 if (BootMenuData->ScrollBarControl.HasScrollBar) {
629 PrintCol = StartCol + Width - 2;
630 PrintRow = StartRow + 2;
631 PrintCharAt (PrintCol, PrintRow, GEOMETRICSHAPE_UP_TRIANGLE);
632 PrintCharAt (PrintCol + 1, PrintRow, BOXDRAW_VERTICAL);
633 PrintRow += (ItemCountPerScreen + 1);
634 PrintCharAt (PrintCol, PrintRow, GEOMETRICSHAPE_DOWN_TRIANGLE);
635 PrintCharAt (PrintCol + 1, PrintRow, BOXDRAW_VERTICAL);
636 }
637
638 gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute);
639 //
640 // Print Selected item
641 //
642 BootMenuSelectItem (BootMenuData->SelectItem, BootMenuData);
643 return EFI_SUCCESS;
644 }
645
646 /**
647 This funciton uses to boot from selected item
648
649 @param BootOptions Pointer to EFI_BOOT_MANAGER_LOAD_OPTION array.
650 @param BootOptionCount Number of boot option.
651 @param SelectItem Current selected item.
652 **/
653 VOID
654 BootFromSelectOption (
655 IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions,
656 IN UINTN BootOptionCount,
657 IN UINTN SelectItem
658 )
659 {
660 UINTN ItemNum;
661 UINTN Index;
662
663 ASSERT (BootOptions != NULL);
664
665 for (ItemNum = 0, Index = 0; Index < BootOptionCount; Index++) {
666 if (IgnoreBootOption (&BootOptions[Index])) {
667 continue;
668 }
669
670 if (ItemNum++ == SelectItem) {
671 EfiBootManagerBoot (&BootOptions[Index]);
672 break;
673 }
674 }
675 }
676
677 /**
678 This function will change video resolution and text mode
679 according to defined setup mode or defined boot mode
680
681 @param IsSetupMode Indicate mode is changed to setup mode or boot mode.
682
683 @retval EFI_SUCCESS Mode is changed successfully.
684 @retval Others Mode failed to be changed.
685
686 **/
687 EFI_STATUS
688 EFIAPI
689 BdsSetConsoleMode (
690 BOOLEAN IsSetupMode
691 )
692 {
693 EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
694 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOut;
695 UINTN SizeOfInfo;
696 EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
697 UINT32 MaxGopMode;
698 UINT32 MaxTextMode;
699 UINT32 ModeNumber;
700 UINT32 NewHorizontalResolution;
701 UINT32 NewVerticalResolution;
702 UINT32 NewColumns;
703 UINT32 NewRows;
704 UINTN HandleCount;
705 EFI_HANDLE *HandleBuffer;
706 EFI_STATUS Status;
707 UINTN Index;
708 UINTN CurrentColumn;
709 UINTN CurrentRow;
710
711 MaxGopMode = 0;
712 MaxTextMode = 0;
713
714 //
715 // Get current video resolution and text mode
716 //
717 Status = gBS->HandleProtocol (
718 gST->ConsoleOutHandle,
719 &gEfiGraphicsOutputProtocolGuid,
720 (VOID**)&GraphicsOutput
721 );
722 if (EFI_ERROR (Status)) {
723 GraphicsOutput = NULL;
724 }
725
726 Status = gBS->HandleProtocol (
727 gST->ConsoleOutHandle,
728 &gEfiSimpleTextOutProtocolGuid,
729 (VOID**)&SimpleTextOut
730 );
731 if (EFI_ERROR (Status)) {
732 SimpleTextOut = NULL;
733 }
734
735 if ((GraphicsOutput == NULL) || (SimpleTextOut == NULL)) {
736 return EFI_UNSUPPORTED;
737 }
738
739 if (IsSetupMode) {
740 //
741 // The requried resolution and text mode is setup mode.
742 //
743 NewHorizontalResolution = mSetupHorizontalResolution;
744 NewVerticalResolution = mSetupVerticalResolution;
745 NewColumns = mSetupTextModeColumn;
746 NewRows = mSetupTextModeRow;
747 } else {
748 //
749 // The required resolution and text mode is boot mode.
750 //
751 NewHorizontalResolution = mBootHorizontalResolution;
752 NewVerticalResolution = mBootVerticalResolution;
753 NewColumns = mBootTextModeColumn;
754 NewRows = mBootTextModeRow;
755 }
756
757 if (GraphicsOutput != NULL) {
758 MaxGopMode = GraphicsOutput->Mode->MaxMode;
759 }
760
761 if (SimpleTextOut != NULL) {
762 MaxTextMode = SimpleTextOut->Mode->MaxMode;
763 }
764
765 //
766 // 1. If current video resolution is same with required video resolution,
767 // video resolution need not be changed.
768 // 1.1. If current text mode is same with required text mode, text mode need not be changed.
769 // 1.2. If current text mode is different from required text mode, text mode need be changed.
770 // 2. If current video resolution is different from required video resolution, we need restart whole console drivers.
771 //
772 for (ModeNumber = 0; ModeNumber < MaxGopMode; ModeNumber++) {
773 Status = GraphicsOutput->QueryMode (
774 GraphicsOutput,
775 ModeNumber,
776 &SizeOfInfo,
777 &Info
778 );
779 if (!EFI_ERROR (Status)) {
780 if ((Info->HorizontalResolution == NewHorizontalResolution) &&
781 (Info->VerticalResolution == NewVerticalResolution)) {
782 if ((GraphicsOutput->Mode->Info->HorizontalResolution == NewHorizontalResolution) &&
783 (GraphicsOutput->Mode->Info->VerticalResolution == NewVerticalResolution)) {
784 //
785 // Current resolution is same with required resolution, check if text mode need be set
786 //
787 Status = SimpleTextOut->QueryMode (SimpleTextOut, SimpleTextOut->Mode->Mode, &CurrentColumn, &CurrentRow);
788 ASSERT_EFI_ERROR (Status);
789 if (CurrentColumn == NewColumns && CurrentRow == NewRows) {
790 //
791 // If current text mode is same with required text mode. Do nothing
792 //
793 FreePool (Info);
794 return EFI_SUCCESS;
795 } else {
796 //
797 // If current text mode is different from requried text mode. Set new video mode
798 //
799 for (Index = 0; Index < MaxTextMode; Index++) {
800 Status = SimpleTextOut->QueryMode (SimpleTextOut, Index, &CurrentColumn, &CurrentRow);
801 if (!EFI_ERROR(Status)) {
802 if ((CurrentColumn == NewColumns) && (CurrentRow == NewRows)) {
803 //
804 // Required text mode is supported, set it.
805 //
806 Status = SimpleTextOut->SetMode (SimpleTextOut, Index);
807 ASSERT_EFI_ERROR (Status);
808 //
809 // Update text mode PCD.
810 //
811 Status = PcdSet32S (PcdConOutColumn, mSetupTextModeColumn);
812 ASSERT_EFI_ERROR (Status);
813 Status = PcdSet32S (PcdConOutRow, mSetupTextModeRow);
814 ASSERT_EFI_ERROR (Status);
815 FreePool (Info);
816 return EFI_SUCCESS;
817 }
818 }
819 }
820 if (Index == MaxTextMode) {
821 //
822 // If requried text mode is not supported, return error.
823 //
824 FreePool (Info);
825 return EFI_UNSUPPORTED;
826 }
827 }
828 } else {
829 //
830 // If current video resolution is not same with the new one, set new video resolution.
831 // In this case, the driver which produces simple text out need be restarted.
832 //
833 Status = GraphicsOutput->SetMode (GraphicsOutput, ModeNumber);
834 if (!EFI_ERROR (Status)) {
835 FreePool (Info);
836 break;
837 }
838 }
839 }
840 FreePool (Info);
841 }
842 }
843
844 if (ModeNumber == MaxGopMode) {
845 //
846 // If the resolution is not supported, return error.
847 //
848 return EFI_UNSUPPORTED;
849 }
850
851 //
852 // Set PCD to Inform GraphicsConsole to change video resolution.
853 // Set PCD to Inform Consplitter to change text mode.
854 //
855 Status = PcdSet32S (PcdVideoHorizontalResolution, NewHorizontalResolution);
856 ASSERT_EFI_ERROR (Status);
857 Status = PcdSet32S (PcdVideoVerticalResolution, NewVerticalResolution);
858 ASSERT_EFI_ERROR (Status);
859 Status = PcdSet32S (PcdConOutColumn, NewColumns);
860 ASSERT_EFI_ERROR (Status);
861 Status = PcdSet32S (PcdConOutRow, NewRows);
862 ASSERT_EFI_ERROR (Status);
863
864 //
865 // Video mode is changed, so restart graphics console driver and higher level driver.
866 // Reconnect graphics console driver and higher level driver.
867 // Locate all the handles with GOP protocol and reconnect it.
868 //
869 Status = gBS->LocateHandleBuffer (
870 ByProtocol,
871 &gEfiSimpleTextOutProtocolGuid,
872 NULL,
873 &HandleCount,
874 &HandleBuffer
875 );
876 if (!EFI_ERROR (Status)) {
877 for (Index = 0; Index < HandleCount; Index++) {
878 gBS->DisconnectController (HandleBuffer[Index], NULL, NULL);
879 }
880 for (Index = 0; Index < HandleCount; Index++) {
881 gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE);
882 }
883 if (HandleBuffer != NULL) {
884 FreePool (HandleBuffer);
885 }
886 }
887
888 return EFI_SUCCESS;
889 }
890
891 /**
892 Display the boot popup menu and allow user select boot item.
893
894 @param ImageHandle The image handle.
895 @param SystemTable The system table.
896
897 @retval EFI_SUCCESS Boot from selected boot option, and return success from boot option
898 @retval EFI_NOT_FOUND User select to enter setup or can not find boot option
899
900 **/
901 EFI_STATUS
902 EFIAPI
903 BootManagerMenuEntry (
904 IN EFI_HANDLE ImageHandle,
905 IN EFI_SYSTEM_TABLE *SystemTable
906 )
907 {
908 EFI_BOOT_MANAGER_LOAD_OPTION *BootOption;
909 UINTN BootOptionCount;
910 EFI_STATUS Status;
911 BOOT_MENU_POPUP_DATA BootMenuData;
912 UINTN Index;
913 EFI_INPUT_KEY Key;
914 BOOLEAN ExitApplication;
915 UINTN SelectItem;
916 EFI_BOOT_LOGO_PROTOCOL *BootLogo;
917 EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
918 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOut;
919 UINTN BootTextColumn;
920 UINTN BootTextRow;
921
922 //
923 // Set Logo status invalid when boot manager menu is launched
924 //
925 BootLogo = NULL;
926 Status = gBS->LocateProtocol (&gEfiBootLogoProtocolGuid, NULL, (VOID **) &BootLogo);
927 if (!EFI_ERROR (Status) && (BootLogo != NULL)) {
928 Status = BootLogo->SetBootLogo (BootLogo, NULL, 0, 0, 0, 0);
929 ASSERT_EFI_ERROR (Status);
930 }
931
932 gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);
933
934 gStringPackHandle = HiiAddPackages (
935 &gEfiCallerIdGuid,
936 gImageHandle,
937 BootManagerMenuAppStrings,
938 NULL
939 );
940 ASSERT (gStringPackHandle != NULL);
941
942 //
943 // Connect all prior to entering the platform setup menu.
944 //
945 EfiBootManagerConnectAll ();
946 EfiBootManagerRefreshAllBootOption ();
947
948 BootOption = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
949
950 if (!mModeInitialized) {
951 //
952 // After the console is ready, get current video resolution
953 // and text mode before launching setup at first time.
954 //
955 Status = gBS->HandleProtocol (
956 gST->ConsoleOutHandle,
957 &gEfiGraphicsOutputProtocolGuid,
958 (VOID**)&GraphicsOutput
959 );
960 if (EFI_ERROR (Status)) {
961 GraphicsOutput = NULL;
962 }
963
964 Status = gBS->HandleProtocol (
965 gST->ConsoleOutHandle,
966 &gEfiSimpleTextOutProtocolGuid,
967 (VOID**)&SimpleTextOut
968 );
969 if (EFI_ERROR (Status)) {
970 SimpleTextOut = NULL;
971 }
972
973 if (GraphicsOutput != NULL) {
974 //
975 // Get current video resolution and text mode.
976 //
977 mBootHorizontalResolution = GraphicsOutput->Mode->Info->HorizontalResolution;
978 mBootVerticalResolution = GraphicsOutput->Mode->Info->VerticalResolution;
979 }
980
981 if (SimpleTextOut != NULL) {
982 Status = SimpleTextOut->QueryMode (
983 SimpleTextOut,
984 SimpleTextOut->Mode->Mode,
985 &BootTextColumn,
986 &BootTextRow
987 );
988 mBootTextModeColumn = (UINT32)BootTextColumn;
989 mBootTextModeRow = (UINT32)BootTextRow;
990 }
991
992 //
993 // Get user defined text mode for setup.
994 //
995 mSetupHorizontalResolution = PcdGet32 (PcdSetupVideoHorizontalResolution);
996 mSetupVerticalResolution = PcdGet32 (PcdSetupVideoVerticalResolution);
997 mSetupTextModeColumn = PcdGet32 (PcdSetupConOutColumn);
998 mSetupTextModeRow = PcdGet32 (PcdSetupConOutRow);
999 mModeInitialized = TRUE;
1000 }
1001
1002 //
1003 // Set back to conventional setup resolution
1004 //
1005 BdsSetConsoleMode (TRUE);
1006
1007 //
1008 // Initialize Boot menu data
1009 //
1010 Status = InitializeBootMenuData (BootOption, BootOptionCount, &BootMenuData);
1011 //
1012 // According to boot menu data to draw boot popup menu
1013 //
1014 DrawBootPopupMenu (&BootMenuData);
1015
1016 //
1017 // check user input to determine want to re-draw or boot from user selected item
1018 //
1019 ExitApplication = FALSE;
1020 while (!ExitApplication) {
1021 gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &Index);
1022 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
1023 if (!EFI_ERROR (Status)) {
1024 switch (Key.UnicodeChar) {
1025
1026 case CHAR_NULL:
1027 switch (Key.ScanCode) {
1028
1029 case SCAN_UP:
1030 SelectItem = BootMenuData.SelectItem == 0 ? BootMenuData.ItemCount - 1 : BootMenuData.SelectItem - 1;
1031 BootMenuSelectItem (SelectItem, &BootMenuData);
1032 break;
1033
1034 case SCAN_DOWN:
1035 SelectItem = BootMenuData.SelectItem == BootMenuData.ItemCount - 1 ? 0 : BootMenuData.SelectItem + 1;
1036 BootMenuSelectItem (SelectItem, &BootMenuData);
1037 break;
1038
1039 case SCAN_ESC:
1040 gST->ConOut->ClearScreen (gST->ConOut);
1041 ExitApplication = TRUE;
1042 //
1043 // Set boot resolution for normal boot
1044 //
1045 BdsSetConsoleMode (FALSE);
1046 break;
1047
1048 default:
1049 break;
1050 }
1051 break;
1052
1053 case CHAR_CARRIAGE_RETURN:
1054 gST->ConOut->ClearScreen (gST->ConOut);
1055 //
1056 // Set boot resolution for normal boot
1057 //
1058 BdsSetConsoleMode (FALSE);
1059 BootFromSelectOption (BootOption, BootOptionCount, BootMenuData.SelectItem);
1060 //
1061 // Back to boot manager menu again, set back to setup resolution
1062 //
1063 BdsSetConsoleMode (TRUE);
1064 DrawBootPopupMenu (&BootMenuData);
1065 break;
1066
1067 default:
1068 break;
1069 }
1070 }
1071 }
1072 EfiBootManagerFreeLoadOptions (BootOption, BootOptionCount);
1073 FreePool (BootMenuData.PtrTokens);
1074
1075 HiiRemovePackages (gStringPackHandle);
1076
1077 return Status;
1078
1079 }