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 } 1082