]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenu.c
9547c7eb5a83e545e0e0a4827fe2c56a6ecf0093
[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 Height;
504 UINTN StartCol;
505 UINTN StartRow;
506 UINTN PrintRow;
507 UINTN PrintCol;
508 UINTN LineWidth;
509 INT32 SavedAttribute;
510 UINTN ItemCountPerScreen;
511
512 gST->ConOut->ClearScreen (gST->ConOut);
513
514 SavedAttribute = gST->ConOut->Mode->Attribute;
515 gST->ConOut->SetAttribute (gST->ConOut, EFI_WHITE | EFI_BACKGROUND_BLUE);
516 Width = BootMenuData->MenuScreen.Width;
517 Height = BootMenuData->MenuScreen.Height;
518 StartCol = BootMenuData->MenuScreen.StartCol;
519 StartRow = BootMenuData->MenuScreen.StartRow;
520 ItemCountPerScreen = BootMenuData->ScrollBarControl.ItemCountPerScreen;
521 PrintRow = StartRow;
522
523 gST->ConOut->EnableCursor (gST->ConOut, FALSE);
524 //
525 // Draw Boot popup menu screen
526 //
527 PrintCharAt (StartCol, PrintRow, BOXDRAW_DOWN_RIGHT);
528 for (Index = 1; Index < Width - 1; Index++) {
529 PrintCharAt (StartCol + Index, PrintRow, BOXDRAW_HORIZONTAL);
530 }
531 PrintCharAt (StartCol + Width - 1, PrintRow, BOXDRAW_DOWN_LEFT);
532
533 //
534 // Draw the screen for title
535 //
536 String = AllocateZeroPool ((Width - 1) * sizeof (CHAR16));
537 ASSERT (String != NULL);
538 for (Index = 0; Index < Width - 2; Index++) {
539 String[Index] = 0x20;
540 }
541
542 for (Index = 0; Index < TITLE_TOKEN_COUNT; Index++) {
543 PrintRow++;
544 PrintCharAt (StartCol, PrintRow, BOXDRAW_VERTICAL);
545 PrintStringAt (StartCol + 1, PrintRow, String);
546 PrintCharAt (StartCol + Width - 1, PrintRow, BOXDRAW_VERTICAL);
547 }
548
549 PrintRow++;
550 PrintCharAt (StartCol, PrintRow, BOXDRAW_VERTICAL_RIGHT);
551 for (Index = 1; Index < Width - 1; Index++) {
552 PrintCharAt (StartCol + Index, PrintRow, BOXDRAW_HORIZONTAL);
553 }
554 PrintCharAt (StartCol + Width - 1, PrintRow, BOXDRAW_VERTICAL_LEFT);
555
556 //
557 // Draw screen for selectable items
558 //
559 for (Index = 0; Index < ItemCountPerScreen; Index++) {
560 PrintRow++;
561 PrintCharAt (StartCol, PrintRow, BOXDRAW_VERTICAL);
562 PrintStringAt (StartCol + 1, PrintRow, String);
563 PrintCharAt (StartCol + Width - 1, PrintRow, BOXDRAW_VERTICAL);
564 }
565
566 PrintRow++;
567 PrintCharAt (StartCol, PrintRow, BOXDRAW_VERTICAL_RIGHT);
568 for (Index = 1; Index < Width - 1; Index++) {
569 PrintCharAt (StartCol + Index, PrintRow, BOXDRAW_HORIZONTAL);
570 }
571 PrintCharAt (StartCol + Width - 1, PrintRow, BOXDRAW_VERTICAL_LEFT);
572
573 //
574 // Draw screen for Help
575 //
576 for (Index = 0; Index < HELP_TOKEN_COUNT; Index++) {
577 PrintRow++;
578 PrintCharAt (StartCol, PrintRow, BOXDRAW_VERTICAL);
579 PrintStringAt (StartCol + 1, PrintRow, String);
580 PrintCharAt (StartCol + Width - 1, PrintRow, BOXDRAW_VERTICAL);
581 }
582 FreePool (String);
583
584 PrintRow++;
585 PrintCharAt (StartCol, PrintRow, BOXDRAW_UP_RIGHT);
586 for (Index = 1; Index < Width - 1; Index++) {
587 PrintCharAt (StartCol + Index, PrintRow, BOXDRAW_HORIZONTAL);
588 }
589 PrintCharAt (StartCol + Width - 1, PrintRow, BOXDRAW_UP_LEFT);
590
591
592 //
593 // print title strings
594 //
595 PrintRow = StartRow + 1;
596 for (Index = 0; Index < TITLE_TOKEN_COUNT; Index++, PrintRow++) {
597 String = HiiGetString (gStringPackHandle, BootMenuData->TitleToken[Index], NULL);
598 LineWidth = GetLineWidth (BootMenuData->TitleToken[Index]);
599 PrintCol = StartCol + (Width - LineWidth) / 2;
600 PrintStringAt (PrintCol, PrintRow, String);
601 FreePool (String);
602 }
603
604 //
605 // print selectable items
606 //
607 PrintCol = StartCol + 1;
608 PrintRow = StartRow + TITLE_TOKEN_COUNT + 2;
609 for (Index = 0; Index < ItemCountPerScreen; Index++, PrintRow++) {
610 String = HiiGetString (gStringPackHandle, BootMenuData->PtrTokens[Index], NULL);
611 PrintStringAt (PrintCol, PrintRow, String);
612 FreePool (String);
613 }
614
615 //
616 // Print Help strings
617 //
618 PrintRow++;
619 for (Index = 0; Index < HELP_TOKEN_COUNT; Index++, PrintRow++) {
620 String = HiiGetString (gStringPackHandle, BootMenuData->HelpToken[Index], NULL);
621 LineWidth = GetLineWidth (BootMenuData->HelpToken[Index]);
622 PrintCol = StartCol + (Width - LineWidth) / 2;
623 PrintStringAt (PrintCol, PrintRow, String);
624 FreePool (String);
625 }
626
627 //
628 // Print scroll bar if has scroll bar
629 //
630 if (BootMenuData->ScrollBarControl.HasScrollBar) {
631 PrintCol = StartCol + Width - 2;
632 PrintRow = StartRow + 2;
633 PrintCharAt (PrintCol, PrintRow, GEOMETRICSHAPE_UP_TRIANGLE);
634 PrintCharAt (PrintCol + 1, PrintRow, BOXDRAW_VERTICAL);
635 PrintRow += (ItemCountPerScreen + 1);
636 PrintCharAt (PrintCol, PrintRow, GEOMETRICSHAPE_DOWN_TRIANGLE);
637 PrintCharAt (PrintCol + 1, PrintRow, BOXDRAW_VERTICAL);
638 }
639
640 gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute);
641 //
642 // Print Selected item
643 //
644 BootMenuSelectItem (BootMenuData->SelectItem, BootMenuData);
645 return EFI_SUCCESS;
646 }
647
648 /**
649 This funciton uses to boot from selected item
650
651 @param BootOptions Pointer to EFI_BOOT_MANAGER_LOAD_OPTION array.
652 @param BootOptionCount Number of boot option.
653 @param SelectItem Current selected item.
654 **/
655 VOID
656 BootFromSelectOption (
657 IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions,
658 IN UINTN BootOptionCount,
659 IN UINTN SelectItem
660 )
661 {
662 UINTN ItemNum;
663 UINTN Index;
664
665 ASSERT (BootOptions != NULL);
666
667 for (ItemNum = 0, Index = 0; Index < BootOptionCount; Index++) {
668 if (IgnoreBootOption (&BootOptions[Index])) {
669 continue;
670 }
671
672 if (ItemNum++ == SelectItem) {
673 EfiBootManagerBoot (&BootOptions[Index]);
674 break;
675 }
676 }
677 }
678
679 /**
680 This function will change video resolution and text mode
681 according to defined setup mode or defined boot mode
682
683 @param IsSetupMode Indicate mode is changed to setup mode or boot mode.
684
685 @retval EFI_SUCCESS Mode is changed successfully.
686 @retval Others Mode failed to be changed.
687
688 **/
689 EFI_STATUS
690 EFIAPI
691 BdsSetConsoleMode (
692 BOOLEAN IsSetupMode
693 )
694 {
695 EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
696 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOut;
697 UINTN SizeOfInfo;
698 EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
699 UINT32 MaxGopMode;
700 UINT32 MaxTextMode;
701 UINT32 ModeNumber;
702 UINT32 NewHorizontalResolution;
703 UINT32 NewVerticalResolution;
704 UINT32 NewColumns;
705 UINT32 NewRows;
706 UINTN HandleCount;
707 EFI_HANDLE *HandleBuffer;
708 EFI_STATUS Status;
709 UINTN Index;
710 UINTN CurrentColumn;
711 UINTN CurrentRow;
712
713 MaxGopMode = 0;
714 MaxTextMode = 0;
715
716 //
717 // Get current video resolution and text mode
718 //
719 Status = gBS->HandleProtocol (
720 gST->ConsoleOutHandle,
721 &gEfiGraphicsOutputProtocolGuid,
722 (VOID**)&GraphicsOutput
723 );
724 if (EFI_ERROR (Status)) {
725 GraphicsOutput = NULL;
726 }
727
728 Status = gBS->HandleProtocol (
729 gST->ConsoleOutHandle,
730 &gEfiSimpleTextOutProtocolGuid,
731 (VOID**)&SimpleTextOut
732 );
733 if (EFI_ERROR (Status)) {
734 SimpleTextOut = NULL;
735 }
736
737 if ((GraphicsOutput == NULL) || (SimpleTextOut == NULL)) {
738 return EFI_UNSUPPORTED;
739 }
740
741 if (IsSetupMode) {
742 //
743 // The requried resolution and text mode is setup mode.
744 //
745 NewHorizontalResolution = mSetupHorizontalResolution;
746 NewVerticalResolution = mSetupVerticalResolution;
747 NewColumns = mSetupTextModeColumn;
748 NewRows = mSetupTextModeRow;
749 } else {
750 //
751 // The required resolution and text mode is boot mode.
752 //
753 NewHorizontalResolution = mBootHorizontalResolution;
754 NewVerticalResolution = mBootVerticalResolution;
755 NewColumns = mBootTextModeColumn;
756 NewRows = mBootTextModeRow;
757 }
758
759 if (GraphicsOutput != NULL) {
760 MaxGopMode = GraphicsOutput->Mode->MaxMode;
761 }
762
763 if (SimpleTextOut != NULL) {
764 MaxTextMode = SimpleTextOut->Mode->MaxMode;
765 }
766
767 //
768 // 1. If current video resolution is same with required video resolution,
769 // video resolution need not be changed.
770 // 1.1. If current text mode is same with required text mode, text mode need not be changed.
771 // 1.2. If current text mode is different from required text mode, text mode need be changed.
772 // 2. If current video resolution is different from required video resolution, we need restart whole console drivers.
773 //
774 for (ModeNumber = 0; ModeNumber < MaxGopMode; ModeNumber++) {
775 Status = GraphicsOutput->QueryMode (
776 GraphicsOutput,
777 ModeNumber,
778 &SizeOfInfo,
779 &Info
780 );
781 if (!EFI_ERROR (Status)) {
782 if ((Info->HorizontalResolution == NewHorizontalResolution) &&
783 (Info->VerticalResolution == NewVerticalResolution)) {
784 if ((GraphicsOutput->Mode->Info->HorizontalResolution == NewHorizontalResolution) &&
785 (GraphicsOutput->Mode->Info->VerticalResolution == NewVerticalResolution)) {
786 //
787 // Current resolution is same with required resolution, check if text mode need be set
788 //
789 Status = SimpleTextOut->QueryMode (SimpleTextOut, SimpleTextOut->Mode->Mode, &CurrentColumn, &CurrentRow);
790 ASSERT_EFI_ERROR (Status);
791 if (CurrentColumn == NewColumns && CurrentRow == NewRows) {
792 //
793 // If current text mode is same with required text mode. Do nothing
794 //
795 FreePool (Info);
796 return EFI_SUCCESS;
797 } else {
798 //
799 // If current text mode is different from requried text mode. Set new video mode
800 //
801 for (Index = 0; Index < MaxTextMode; Index++) {
802 Status = SimpleTextOut->QueryMode (SimpleTextOut, Index, &CurrentColumn, &CurrentRow);
803 if (!EFI_ERROR(Status)) {
804 if ((CurrentColumn == NewColumns) && (CurrentRow == NewRows)) {
805 //
806 // Required text mode is supported, set it.
807 //
808 Status = SimpleTextOut->SetMode (SimpleTextOut, Index);
809 ASSERT_EFI_ERROR (Status);
810 //
811 // Update text mode PCD.
812 //
813 Status = PcdSet32S (PcdConOutColumn, mSetupTextModeColumn);
814 ASSERT_EFI_ERROR (Status);
815 Status = PcdSet32S (PcdConOutRow, mSetupTextModeRow);
816 ASSERT_EFI_ERROR (Status);
817 FreePool (Info);
818 return EFI_SUCCESS;
819 }
820 }
821 }
822 if (Index == MaxTextMode) {
823 //
824 // If requried text mode is not supported, return error.
825 //
826 FreePool (Info);
827 return EFI_UNSUPPORTED;
828 }
829 }
830 } else {
831 //
832 // If current video resolution is not same with the new one, set new video resolution.
833 // In this case, the driver which produces simple text out need be restarted.
834 //
835 Status = GraphicsOutput->SetMode (GraphicsOutput, ModeNumber);
836 if (!EFI_ERROR (Status)) {
837 FreePool (Info);
838 break;
839 }
840 }
841 }
842 FreePool (Info);
843 }
844 }
845
846 if (ModeNumber == MaxGopMode) {
847 //
848 // If the resolution is not supported, return error.
849 //
850 return EFI_UNSUPPORTED;
851 }
852
853 //
854 // Set PCD to Inform GraphicsConsole to change video resolution.
855 // Set PCD to Inform Consplitter to change text mode.
856 //
857 Status = PcdSet32S (PcdVideoHorizontalResolution, NewHorizontalResolution);
858 ASSERT_EFI_ERROR (Status);
859 Status = PcdSet32S (PcdVideoVerticalResolution, NewVerticalResolution);
860 ASSERT_EFI_ERROR (Status);
861 Status = PcdSet32S (PcdConOutColumn, NewColumns);
862 ASSERT_EFI_ERROR (Status);
863 Status = PcdSet32S (PcdConOutRow, NewRows);
864 ASSERT_EFI_ERROR (Status);
865
866 //
867 // Video mode is changed, so restart graphics console driver and higher level driver.
868 // Reconnect graphics console driver and higher level driver.
869 // Locate all the handles with GOP protocol and reconnect it.
870 //
871 Status = gBS->LocateHandleBuffer (
872 ByProtocol,
873 &gEfiSimpleTextOutProtocolGuid,
874 NULL,
875 &HandleCount,
876 &HandleBuffer
877 );
878 if (!EFI_ERROR (Status)) {
879 for (Index = 0; Index < HandleCount; Index++) {
880 gBS->DisconnectController (HandleBuffer[Index], NULL, NULL);
881 }
882 for (Index = 0; Index < HandleCount; Index++) {
883 gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE);
884 }
885 if (HandleBuffer != NULL) {
886 FreePool (HandleBuffer);
887 }
888 }
889
890 return EFI_SUCCESS;
891 }
892
893 /**
894 Display the boot popup menu and allow user select boot item.
895
896 @param ImageHandle The image handle.
897 @param SystemTable The system table.
898
899 @retval EFI_SUCCESS Boot from selected boot option, and return success from boot option
900 @retval EFI_NOT_FOUND User select to enter setup or can not find boot option
901
902 **/
903 EFI_STATUS
904 EFIAPI
905 BootManagerMenuEntry (
906 IN EFI_HANDLE ImageHandle,
907 IN EFI_SYSTEM_TABLE *SystemTable
908 )
909 {
910 EFI_BOOT_MANAGER_LOAD_OPTION *BootOption;
911 UINTN BootOptionCount;
912 EFI_STATUS Status;
913 BOOT_MENU_POPUP_DATA BootMenuData;
914 UINTN Index;
915 EFI_INPUT_KEY Key;
916 BOOLEAN ExitApplication;
917 UINTN SelectItem;
918 EFI_BOOT_LOGO_PROTOCOL *BootLogo;
919 EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
920 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOut;
921 UINTN BootTextColumn;
922 UINTN BootTextRow;
923
924 //
925 // Set Logo status invalid when boot manager menu is launched
926 //
927 BootLogo = NULL;
928 Status = gBS->LocateProtocol (&gEfiBootLogoProtocolGuid, NULL, (VOID **) &BootLogo);
929 if (!EFI_ERROR (Status) && (BootLogo != NULL)) {
930 Status = BootLogo->SetBootLogo (BootLogo, NULL, 0, 0, 0, 0);
931 ASSERT_EFI_ERROR (Status);
932 }
933
934 gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);
935
936 gStringPackHandle = HiiAddPackages (
937 &gEfiCallerIdGuid,
938 gImageHandle,
939 BootManagerMenuAppStrings,
940 NULL
941 );
942 ASSERT (gStringPackHandle != NULL);
943
944 //
945 // Connect all prior to entering the platform setup menu.
946 //
947 EfiBootManagerConnectAll ();
948 EfiBootManagerRefreshAllBootOption ();
949
950 BootOption = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
951
952 if (!mModeInitialized) {
953 //
954 // After the console is ready, get current video resolution
955 // and text mode before launching setup at first time.
956 //
957 Status = gBS->HandleProtocol (
958 gST->ConsoleOutHandle,
959 &gEfiGraphicsOutputProtocolGuid,
960 (VOID**)&GraphicsOutput
961 );
962 if (EFI_ERROR (Status)) {
963 GraphicsOutput = NULL;
964 }
965
966 Status = gBS->HandleProtocol (
967 gST->ConsoleOutHandle,
968 &gEfiSimpleTextOutProtocolGuid,
969 (VOID**)&SimpleTextOut
970 );
971 if (EFI_ERROR (Status)) {
972 SimpleTextOut = NULL;
973 }
974
975 if (GraphicsOutput != NULL) {
976 //
977 // Get current video resolution and text mode.
978 //
979 mBootHorizontalResolution = GraphicsOutput->Mode->Info->HorizontalResolution;
980 mBootVerticalResolution = GraphicsOutput->Mode->Info->VerticalResolution;
981 }
982
983 if (SimpleTextOut != NULL) {
984 Status = SimpleTextOut->QueryMode (
985 SimpleTextOut,
986 SimpleTextOut->Mode->Mode,
987 &BootTextColumn,
988 &BootTextRow
989 );
990 mBootTextModeColumn = (UINT32)BootTextColumn;
991 mBootTextModeRow = (UINT32)BootTextRow;
992 }
993
994 //
995 // Get user defined text mode for setup.
996 //
997 mSetupHorizontalResolution = PcdGet32 (PcdSetupVideoHorizontalResolution);
998 mSetupVerticalResolution = PcdGet32 (PcdSetupVideoVerticalResolution);
999 mSetupTextModeColumn = PcdGet32 (PcdSetupConOutColumn);
1000 mSetupTextModeRow = PcdGet32 (PcdSetupConOutRow);
1001 mModeInitialized = TRUE;
1002 }
1003
1004 //
1005 // Set back to conventional setup resolution
1006 //
1007 BdsSetConsoleMode (TRUE);
1008
1009 //
1010 // Initialize Boot menu data
1011 //
1012 Status = InitializeBootMenuData (BootOption, BootOptionCount, &BootMenuData);
1013 //
1014 // According to boot menu data to draw boot popup menu
1015 //
1016 DrawBootPopupMenu (&BootMenuData);
1017
1018 //
1019 // check user input to determine want to re-draw or boot from user selected item
1020 //
1021 ExitApplication = FALSE;
1022 while (!ExitApplication) {
1023 gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &Index);
1024 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
1025 if (!EFI_ERROR (Status)) {
1026 switch (Key.UnicodeChar) {
1027
1028 case CHAR_NULL:
1029 switch (Key.ScanCode) {
1030
1031 case SCAN_UP:
1032 SelectItem = BootMenuData.SelectItem == 0 ? BootMenuData.ItemCount - 1 : BootMenuData.SelectItem - 1;
1033 BootMenuSelectItem (SelectItem, &BootMenuData);
1034 break;
1035
1036 case SCAN_DOWN:
1037 SelectItem = BootMenuData.SelectItem == BootMenuData.ItemCount - 1 ? 0 : BootMenuData.SelectItem + 1;
1038 BootMenuSelectItem (SelectItem, &BootMenuData);
1039 break;
1040
1041 case SCAN_ESC:
1042 gST->ConOut->ClearScreen (gST->ConOut);
1043 ExitApplication = TRUE;
1044 //
1045 // Set boot resolution for normal boot
1046 //
1047 BdsSetConsoleMode (FALSE);
1048 break;
1049
1050 default:
1051 break;
1052 }
1053 break;
1054
1055 case CHAR_CARRIAGE_RETURN:
1056 gST->ConOut->ClearScreen (gST->ConOut);
1057 //
1058 // Set boot resolution for normal boot
1059 //
1060 BdsSetConsoleMode (FALSE);
1061 BootFromSelectOption (BootOption, BootOptionCount, BootMenuData.SelectItem);
1062 //
1063 // Back to boot manager menu again, set back to setup resolution
1064 //
1065 BdsSetConsoleMode (TRUE);
1066 DrawBootPopupMenu (&BootMenuData);
1067 break;
1068
1069 default:
1070 break;
1071 }
1072 }
1073 }
1074 EfiBootManagerFreeLoadOptions (BootOption, BootOptionCount);
1075 FreePool (BootMenuData.PtrTokens);
1076
1077 HiiRemovePackages (gStringPackHandle);
1078
1079 return Status;
1080
1081 }