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