1/** @file 2 The application to show the Boot Manager Menu. 3 4Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.<BR> 5This program and the accompanying materials 6are licensed and made available under the terms and conditions of the BSD License 7which accompanies this distribution. The full text of the license may be found at 8http://opensource.org/licenses/bsd-license.php 9 10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 12 13**/ 14 15#include "BootManagerMenu.h" 16 17EFI_HII_HANDLE gStringPackHandle; 18 19BOOLEAN mModeInitialized = FALSE; 20 21// 22// Boot video resolution and text mode. 23// 24UINT32 mBootHorizontalResolution = 0; 25UINT32 mBootVerticalResolution = 0; 26UINT32 mBootTextModeColumn = 0; 27UINT32 mBootTextModeRow = 0; 28// 29// BIOS setup video resolution and text mode. 30// 31UINT32 mSetupTextModeColumn = 0; 32UINT32 mSetupTextModeRow = 0; 33UINT32 mSetupHorizontalResolution = 0; 34UINT32 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**/ 47UINTN 48PrintStringAt ( 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 character 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**/ 70UINTN 71PrintCharAt ( 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 language 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**/ 90UINTN 91GetLineWidth ( 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 processed. 151 152 @return EFI_SUCCESS calculate boot menu information successful. 153 @retval EFI_INVALID_PARAMETER Input parameter is invalid 154 155**/ 156EFI_STATUS 157InitializeBootMenuScreen ( 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 function 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**/ 230BOOLEAN 231IsBootManagerMenu ( 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 option. 252 @retval FALSE Do not ignore the boot option. 253**/ 254BOOLEAN 255IgnoreBootOption ( 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 function 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**/ 299EFI_STATUS 300InitializeBootMenuData ( 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 processed 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**/ 354EFI_STATUS 355BootMenuSelectItem ( 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 function 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**/ 495EFI_STATUS 496DrawBootPopupMenu ( 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 function 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**/ 653VOID 654BootFromSelectOption ( 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**/ 687EFI_STATUS 688EFIAPI 689BdsSetConsoleMode ( 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 required 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 required 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 required 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**/ 901EFI_STATUS 902EFIAPI 903BootManagerMenuEntry ( 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} 1080