Home | History | Annotate | Download | only in BootManagerLib
      1 /** @file
      2   The boot manager reference implementation
      3 
      4 Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>
      5 This program and the accompanying materials are licensed and made available under
      6 the terms and conditions of the BSD License that accompanies this distribution.
      7 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 "BootManager.h"
     16 
     17 UINT16             mKeyInput;
     18 EFI_GUID           mBootManagerGuid = BOOT_MANAGER_FORMSET_GUID;
     19 //
     20 // Boot video resolution and text mode.
     21 //
     22 UINT32    mBmBootHorizontalResolution    = 0;
     23 UINT32    mBmBootVerticalResolution      = 0;
     24 UINT32    mBmBootTextModeColumn          = 0;
     25 UINT32    mBmBootTextModeRow             = 0;
     26 //
     27 // BIOS setup video resolution and text mode.
     28 //
     29 UINT32    mBmSetupTextModeColumn         = 0;
     30 UINT32    mBmSetupTextModeRow            = 0;
     31 UINT32    mBmSetupHorizontalResolution   = 0;
     32 UINT32    mBmSetupVerticalResolution     = 0;
     33 
     34 CHAR16             *mDeviceTypeStr[] = {
     35   L"Legacy BEV",
     36   L"Legacy Floppy",
     37   L"Legacy Hard Drive",
     38   L"Legacy CD ROM",
     39   L"Legacy PCMCIA",
     40   L"Legacy USB",
     41   L"Legacy Embedded Network",
     42   L"Legacy Unknown Device"
     43 };
     44 
     45 HII_VENDOR_DEVICE_PATH  mBootManagerHiiVendorDevicePath = {
     46   {
     47     {
     48       HARDWARE_DEVICE_PATH,
     49       HW_VENDOR_DP,
     50       {
     51         (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
     52         (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
     53       }
     54     },
     55     //
     56     // {1DDDBE15-481D-4d2b-8277-B191EAF66525}
     57     //
     58     { 0x1dddbe15, 0x481d, 0x4d2b, { 0x82, 0x77, 0xb1, 0x91, 0xea, 0xf6, 0x65, 0x25 } }
     59   },
     60   {
     61     END_DEVICE_PATH_TYPE,
     62     END_ENTIRE_DEVICE_PATH_SUBTYPE,
     63     {
     64       (UINT8) (END_DEVICE_PATH_LENGTH),
     65       (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
     66     }
     67   }
     68 };
     69 
     70 BOOT_MANAGER_CALLBACK_DATA  gBootManagerPrivate = {
     71   BOOT_MANAGER_CALLBACK_DATA_SIGNATURE,
     72   NULL,
     73   NULL,
     74   {
     75     BootManagerExtractConfig,
     76     BootManagerRouteConfig,
     77     BootManagerCallback
     78   }
     79 };
     80 
     81 /**
     82   This function will change video resolution and text mode
     83   according to defined setup mode or defined boot mode
     84 
     85   @param  IsSetupMode   Indicate mode is changed to setup mode or boot mode.
     86 
     87   @retval  EFI_SUCCESS  Mode is changed successfully.
     88   @retval  Others             Mode failed to be changed.
     89 
     90 **/
     91 EFI_STATUS
     92 EFIAPI
     93 BmBdsSetConsoleMode (
     94   BOOLEAN  IsSetupMode
     95   )
     96 {
     97   EFI_GRAPHICS_OUTPUT_PROTOCOL          *GraphicsOutput;
     98   EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL       *SimpleTextOut;
     99   UINTN                                 SizeOfInfo;
    100   EFI_GRAPHICS_OUTPUT_MODE_INFORMATION  *Info;
    101   UINT32                                MaxGopMode;
    102   UINT32                                MaxTextMode;
    103   UINT32                                ModeNumber;
    104   UINT32                                NewHorizontalResolution;
    105   UINT32                                NewVerticalResolution;
    106   UINT32                                NewColumns;
    107   UINT32                                NewRows;
    108   UINTN                                 HandleCount;
    109   EFI_HANDLE                            *HandleBuffer;
    110   EFI_STATUS                            Status;
    111   UINTN                                 Index;
    112   UINTN                                 CurrentColumn;
    113   UINTN                                 CurrentRow;
    114 
    115   MaxGopMode  = 0;
    116   MaxTextMode = 0;
    117 
    118   //
    119   // Get current video resolution and text mode
    120   //
    121   Status = gBS->HandleProtocol (
    122                   gST->ConsoleOutHandle,
    123                   &gEfiGraphicsOutputProtocolGuid,
    124                   (VOID**)&GraphicsOutput
    125                   );
    126   if (EFI_ERROR (Status)) {
    127     GraphicsOutput = NULL;
    128   }
    129 
    130   Status = gBS->HandleProtocol (
    131                   gST->ConsoleOutHandle,
    132                   &gEfiSimpleTextOutProtocolGuid,
    133                   (VOID**)&SimpleTextOut
    134                   );
    135   if (EFI_ERROR (Status)) {
    136     SimpleTextOut = NULL;
    137   }
    138 
    139   if ((GraphicsOutput == NULL) || (SimpleTextOut == NULL)) {
    140     return EFI_UNSUPPORTED;
    141   }
    142 
    143   if (IsSetupMode) {
    144     //
    145     // The requried resolution and text mode is setup mode.
    146     //
    147     NewHorizontalResolution = mBmSetupHorizontalResolution;
    148     NewVerticalResolution   = mBmSetupVerticalResolution;
    149     NewColumns              = mBmSetupTextModeColumn;
    150     NewRows                 = mBmSetupTextModeRow;
    151   } else {
    152     //
    153     // The required resolution and text mode is boot mode.
    154     //
    155     NewHorizontalResolution = mBmBootHorizontalResolution;
    156     NewVerticalResolution   = mBmBootVerticalResolution;
    157     NewColumns              = mBmBootTextModeColumn;
    158     NewRows                 = mBmBootTextModeRow;
    159   }
    160 
    161   if (GraphicsOutput != NULL) {
    162     MaxGopMode  = GraphicsOutput->Mode->MaxMode;
    163   }
    164 
    165   if (SimpleTextOut != NULL) {
    166     MaxTextMode = SimpleTextOut->Mode->MaxMode;
    167   }
    168 
    169   //
    170   // 1. If current video resolution is same with required video resolution,
    171   //    video resolution need not be changed.
    172   //    1.1. If current text mode is same with required text mode, text mode need not be changed.
    173   //    1.2. If current text mode is different from required text mode, text mode need be changed.
    174   // 2. If current video resolution is different from required video resolution, we need restart whole console drivers.
    175   //
    176   for (ModeNumber = 0; ModeNumber < MaxGopMode; ModeNumber++) {
    177     Status = GraphicsOutput->QueryMode (
    178                        GraphicsOutput,
    179                        ModeNumber,
    180                        &SizeOfInfo,
    181                        &Info
    182                        );
    183     if (!EFI_ERROR (Status)) {
    184       if ((Info->HorizontalResolution == NewHorizontalResolution) &&
    185           (Info->VerticalResolution == NewVerticalResolution)) {
    186         if ((GraphicsOutput->Mode->Info->HorizontalResolution == NewHorizontalResolution) &&
    187             (GraphicsOutput->Mode->Info->VerticalResolution == NewVerticalResolution)) {
    188           //
    189           // Current resolution is same with required resolution, check if text mode need be set
    190           //
    191           Status = SimpleTextOut->QueryMode (SimpleTextOut, SimpleTextOut->Mode->Mode, &CurrentColumn, &CurrentRow);
    192           ASSERT_EFI_ERROR (Status);
    193           if (CurrentColumn == NewColumns && CurrentRow == NewRows) {
    194             //
    195             // If current text mode is same with required text mode. Do nothing
    196             //
    197             FreePool (Info);
    198             return EFI_SUCCESS;
    199           } else {
    200             //
    201             // If current text mode is different from requried text mode.  Set new video mode
    202             //
    203             for (Index = 0; Index < MaxTextMode; Index++) {
    204               Status = SimpleTextOut->QueryMode (SimpleTextOut, Index, &CurrentColumn, &CurrentRow);
    205               if (!EFI_ERROR(Status)) {
    206                 if ((CurrentColumn == NewColumns) && (CurrentRow == NewRows)) {
    207                   //
    208                   // Required text mode is supported, set it.
    209                   //
    210                   Status = SimpleTextOut->SetMode (SimpleTextOut, Index);
    211                   ASSERT_EFI_ERROR (Status);
    212                   //
    213                   // Update text mode PCD.
    214                   //
    215                   Status = PcdSet32S (PcdConOutColumn, mBmSetupTextModeColumn);
    216                   ASSERT_EFI_ERROR (Status);
    217                   Status = PcdSet32S (PcdConOutRow, mBmSetupTextModeRow);
    218                   ASSERT_EFI_ERROR (Status);
    219                   FreePool (Info);
    220                   return EFI_SUCCESS;
    221                 }
    222               }
    223             }
    224             if (Index == MaxTextMode) {
    225               //
    226               // If requried text mode is not supported, return error.
    227               //
    228               FreePool (Info);
    229               return EFI_UNSUPPORTED;
    230             }
    231           }
    232         } else {
    233           //
    234           // If current video resolution is not same with the new one, set new video resolution.
    235           // In this case, the driver which produces simple text out need be restarted.
    236           //
    237           Status = GraphicsOutput->SetMode (GraphicsOutput, ModeNumber);
    238           if (!EFI_ERROR (Status)) {
    239             FreePool (Info);
    240             break;
    241           }
    242         }
    243       }
    244       FreePool (Info);
    245     }
    246   }
    247 
    248   if (ModeNumber == MaxGopMode) {
    249     //
    250     // If the resolution is not supported, return error.
    251     //
    252     return EFI_UNSUPPORTED;
    253   }
    254 
    255   //
    256   // Set PCD to Inform GraphicsConsole to change video resolution.
    257   // Set PCD to Inform Consplitter to change text mode.
    258   //
    259   Status = PcdSet32S (PcdVideoHorizontalResolution, NewHorizontalResolution);
    260   ASSERT_EFI_ERROR (Status);
    261   Status = PcdSet32S (PcdVideoVerticalResolution, NewVerticalResolution);
    262   ASSERT_EFI_ERROR (Status);
    263   Status = PcdSet32S (PcdConOutColumn, NewColumns);
    264   ASSERT_EFI_ERROR (Status);
    265   Status = PcdSet32S (PcdConOutRow, NewRows);
    266   ASSERT_EFI_ERROR (Status);
    267 
    268   //
    269   // Video mode is changed, so restart graphics console driver and higher level driver.
    270   // Reconnect graphics console driver and higher level driver.
    271   // Locate all the handles with GOP protocol and reconnect it.
    272   //
    273   Status = gBS->LocateHandleBuffer (
    274                    ByProtocol,
    275                    &gEfiSimpleTextOutProtocolGuid,
    276                    NULL,
    277                    &HandleCount,
    278                    &HandleBuffer
    279                    );
    280   if (!EFI_ERROR (Status)) {
    281     for (Index = 0; Index < HandleCount; Index++) {
    282       gBS->DisconnectController (HandleBuffer[Index], NULL, NULL);
    283     }
    284     for (Index = 0; Index < HandleCount; Index++) {
    285       gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE);
    286     }
    287     if (HandleBuffer != NULL) {
    288       FreePool (HandleBuffer);
    289     }
    290   }
    291 
    292   return EFI_SUCCESS;
    293 }
    294 
    295 /**
    296   Group the legacy boot options in the BootOption.
    297 
    298   The routine assumes the boot options in the beginning that covers all the device
    299   types are ordered properly and re-position the following boot options just after
    300   the corresponding boot options with the same device type.
    301   For example:
    302   1. Input  = [Harddisk1 CdRom2 Efi1 Harddisk0 CdRom0 CdRom1 Harddisk2 Efi0]
    303      Assuming [Harddisk1 CdRom2 Efi1] is ordered properly
    304      Output = [Harddisk1 Harddisk0 Harddisk2 CdRom2 CdRom0 CdRom1 Efi1 Efi0]
    305 
    306   2. Input  = [Efi1 Efi0 CdRom1 Harddisk0 Harddisk1 Harddisk2 CdRom0 CdRom2]
    307      Assuming [Efi1 Efi0 CdRom1 Harddisk0] is ordered properly
    308      Output = [Efi1 Efi0 CdRom1 CdRom0 CdRom2 Harddisk0 Harddisk1 Harddisk2]
    309 
    310 **/
    311 VOID
    312 GroupMultipleLegacyBootOption4SameType (
    313   VOID
    314   )
    315 {
    316   EFI_STATUS                   Status;
    317   UINTN                        Index;
    318   UINTN                        DeviceIndex;
    319   UINTN                        DeviceTypeIndex[7];
    320   UINTN                        *NextIndex;
    321   UINT16                       OptionNumber;
    322   UINT16                       *BootOrder;
    323   UINTN                        BootOrderSize;
    324   CHAR16                       OptionName[sizeof ("Boot####")];
    325   EFI_BOOT_MANAGER_LOAD_OPTION BootOption;
    326 
    327   SetMem (DeviceTypeIndex, sizeof (DeviceTypeIndex), 0xff);
    328 
    329   GetEfiGlobalVariable2 (L"BootOrder", (VOID **) &BootOrder, &BootOrderSize);
    330   if (BootOrder == NULL) {
    331     return;
    332   }
    333 
    334   for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {
    335     UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", BootOrder[Index]);
    336     Status = EfiBootManagerVariableToLoadOption (OptionName, &BootOption);
    337     ASSERT_EFI_ERROR (Status);
    338 
    339     if ((DevicePathType (BootOption.FilePath) == BBS_DEVICE_PATH) &&
    340         (DevicePathSubType (BootOption.FilePath) == BBS_BBS_DP)) {
    341       //
    342       // Legacy Boot Option
    343       //
    344       DEBUG ((EFI_D_ERROR, "[BootManagerDxe] ==== Find Legacy Boot Option  0x%x! ==== \n", Index));
    345       ASSERT ((((BBS_BBS_DEVICE_PATH *) BootOption.FilePath)->DeviceType & 0xF) < sizeof (DeviceTypeIndex) / sizeof (DeviceTypeIndex[0]));
    346       NextIndex = &DeviceTypeIndex[((BBS_BBS_DEVICE_PATH *) BootOption.FilePath)->DeviceType & 0xF];
    347 
    348       if (*NextIndex == (UINTN) -1) {
    349         //
    350         // *NextIndex is the Index in BootOrder to put the next Option Number for the same type
    351         //
    352         *NextIndex = Index + 1;
    353       } else {
    354         //
    355         // insert the current boot option before *NextIndex, causing [*Next .. Index] shift right one position
    356         //
    357         OptionNumber = BootOrder[Index];
    358         CopyMem (&BootOrder[*NextIndex + 1], &BootOrder[*NextIndex], (Index - *NextIndex) * sizeof (UINT16));
    359         BootOrder[*NextIndex] = OptionNumber;
    360 
    361         //
    362         // Update the DeviceTypeIndex array to reflect the right shift operation
    363         //
    364         for (DeviceIndex = 0; DeviceIndex < sizeof (DeviceTypeIndex) / sizeof (DeviceTypeIndex[0]); DeviceIndex++) {
    365           if (DeviceTypeIndex[DeviceIndex] != (UINTN) -1 && DeviceTypeIndex[DeviceIndex] >= *NextIndex) {
    366             DeviceTypeIndex[DeviceIndex]++;
    367           }
    368         }
    369       }
    370     }
    371     EfiBootManagerFreeLoadOption (&BootOption);
    372   }
    373 
    374   gRT->SetVariable (
    375          L"BootOrder",
    376          &gEfiGlobalVariableGuid,
    377          VAR_FLAG,
    378          BootOrderSize,
    379          BootOrder
    380          );
    381   FreePool (BootOrder);
    382 }
    383 
    384 /**
    385   This function converts an input device structure to a Unicode string.
    386 
    387   @param DevPath                  A pointer to the device path structure.
    388 
    389   @return A new allocated Unicode string that represents the device path.
    390 
    391 **/
    392 CHAR16 *
    393 BmDevicePathToStr (
    394   IN EFI_DEVICE_PATH_PROTOCOL     *DevPath
    395   )
    396 {
    397   EFI_STATUS                       Status;
    398   CHAR16                           *ToText;
    399   EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *DevPathToText;
    400 
    401   if (DevPath == NULL) {
    402     return NULL;
    403   }
    404 
    405   Status = gBS->LocateProtocol (
    406                   &gEfiDevicePathToTextProtocolGuid,
    407                   NULL,
    408                   (VOID **) &DevPathToText
    409                   );
    410   ASSERT_EFI_ERROR (Status);
    411   ToText = DevPathToText->ConvertDevicePathToText (
    412                             DevPath,
    413                             FALSE,
    414                             TRUE
    415                             );
    416   ASSERT (ToText != NULL);
    417   return ToText;
    418 }
    419 
    420 /**
    421   This function invokes Boot Manager. If all devices have not a chance to be connected,
    422   the connect all will be triggered. It then enumerate all boot options. If
    423   a boot option from the Boot Manager page is selected, Boot Manager will boot
    424   from this boot option.
    425 
    426 **/
    427 VOID
    428 UpdateBootManager (
    429   VOID
    430   )
    431 {
    432   UINTN                         Index;
    433   EFI_BOOT_MANAGER_LOAD_OPTION  *BootOption;
    434   UINTN                         BootOptionCount;
    435   EFI_STRING_ID                 Token;
    436   CHAR16                        *HelpString;
    437   EFI_STRING_ID                 HelpToken;
    438   UINT16                        *TempStr;
    439   EFI_HII_HANDLE                HiiHandle;
    440   UINTN                         TempSize;
    441   VOID                          *StartOpCodeHandle;
    442   VOID                          *EndOpCodeHandle;
    443   EFI_IFR_GUID_LABEL            *StartLabel;
    444   EFI_IFR_GUID_LABEL            *EndLabel;
    445   UINT16                        DeviceType;
    446   BOOLEAN                       IsLegacyOption;
    447   BOOLEAN                       NeedEndOp;
    448   UINTN                         MaxLen;
    449 
    450   DeviceType = (UINT16) -1;
    451 
    452   EfiBootManagerConnectAll ();
    453 
    454   //
    455   // for better user experience
    456   // 1. User changes HD configuration (e.g.: unplug HDD), here we have a chance to remove the HDD boot option
    457   // 2. User enables/disables UEFI PXE, here we have a chance to add/remove EFI Network boot option
    458   //
    459   EfiBootManagerRefreshAllBootOption ();
    460 
    461   //
    462   // BdsDxe doesn't group the legacy boot options for the same device type
    463   // It's UI's choice.
    464   //
    465   GroupMultipleLegacyBootOption4SameType ();
    466 
    467   BootOption = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
    468 
    469   HiiHandle = gBootManagerPrivate.HiiHandle;
    470 
    471   //
    472   // Allocate space for creation of UpdateData Buffer
    473   //
    474   StartOpCodeHandle = HiiAllocateOpCodeHandle ();
    475   ASSERT (StartOpCodeHandle != NULL);
    476 
    477   EndOpCodeHandle = HiiAllocateOpCodeHandle ();
    478   ASSERT (EndOpCodeHandle != NULL);
    479 
    480   //
    481   // Create Hii Extend Label OpCode as the start opcode
    482   //
    483   StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
    484   StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
    485   StartLabel->Number       = LABEL_BOOT_OPTION;
    486 
    487   //
    488   // Create Hii Extend Label OpCode as the end opcode
    489   //
    490   EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
    491   EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
    492   EndLabel->Number       = LABEL_BOOT_OPTION_END;
    493   mKeyInput = 0;
    494   NeedEndOp = FALSE;
    495   for (Index = 0; Index < BootOptionCount; Index++) {
    496     //
    497     // At this stage we are creating a menu entry, thus the Keys are reproduceable
    498     //
    499     mKeyInput++;
    500 
    501     //
    502     // Don't display the hidden/inactive boot option
    503     //
    504     if (((BootOption[Index].Attributes & LOAD_OPTION_HIDDEN) != 0) || ((BootOption[Index].Attributes & LOAD_OPTION_ACTIVE) == 0)) {
    505       continue;
    506     }
    507 
    508     //
    509     // Group the legacy boot option in the sub title created dynamically
    510     //
    511     IsLegacyOption = (BOOLEAN) (
    512                        (DevicePathType (BootOption[Index].FilePath) == BBS_DEVICE_PATH) &&
    513                        (DevicePathSubType (BootOption[Index].FilePath) == BBS_BBS_DP)
    514                        );
    515 
    516     if (!IsLegacyOption && NeedEndOp) {
    517       NeedEndOp = FALSE;
    518       HiiCreateEndOpCode (StartOpCodeHandle);
    519     }
    520 
    521     if (IsLegacyOption && DeviceType != ((BBS_BBS_DEVICE_PATH *) BootOption[Index].FilePath)->DeviceType) {
    522       if (NeedEndOp) {
    523         HiiCreateEndOpCode (StartOpCodeHandle);
    524       }
    525 
    526       DeviceType = ((BBS_BBS_DEVICE_PATH *) BootOption[Index].FilePath)->DeviceType;
    527       Token      = HiiSetString (
    528                      HiiHandle,
    529                      0,
    530                      mDeviceTypeStr[
    531                        MIN (DeviceType & 0xF, sizeof (mDeviceTypeStr) / sizeof (mDeviceTypeStr[0]) - 1)
    532                        ],
    533                      NULL
    534                      );
    535       HiiCreateSubTitleOpCode (StartOpCodeHandle, Token, 0, 0, 1);
    536       NeedEndOp = TRUE;
    537     }
    538 
    539     ASSERT (BootOption[Index].Description != NULL);
    540 
    541     Token = HiiSetString (HiiHandle, 0, BootOption[Index].Description, NULL);
    542 
    543     TempStr = BmDevicePathToStr (BootOption[Index].FilePath);
    544     TempSize = StrSize (TempStr);
    545     HelpString = AllocateZeroPool (TempSize + StrSize (L"Device Path : "));
    546     MaxLen = (TempSize + StrSize (L"Device Path : "))/sizeof(CHAR16);
    547     ASSERT (HelpString != NULL);
    548     StrCatS (HelpString, MaxLen, L"Device Path : ");
    549     StrCatS (HelpString, MaxLen, TempStr);
    550 
    551     HelpToken = HiiSetString (HiiHandle, 0, HelpString, NULL);
    552 
    553     HiiCreateActionOpCode (
    554       StartOpCodeHandle,
    555       mKeyInput,
    556       Token,
    557       HelpToken,
    558       EFI_IFR_FLAG_CALLBACK,
    559       0
    560       );
    561   }
    562 
    563   if (NeedEndOp) {
    564     HiiCreateEndOpCode (StartOpCodeHandle);
    565   }
    566 
    567   HiiUpdateForm (
    568     HiiHandle,
    569     &mBootManagerGuid,
    570     BOOT_MANAGER_FORM_ID,
    571     StartOpCodeHandle,
    572     EndOpCodeHandle
    573     );
    574 
    575   HiiFreeOpCodeHandle (StartOpCodeHandle);
    576   HiiFreeOpCodeHandle (EndOpCodeHandle);
    577 
    578   EfiBootManagerFreeLoadOptions (BootOption, BootOptionCount);
    579 }
    580 
    581 /**
    582   This function allows a caller to extract the current configuration for one
    583   or more named elements from the target driver.
    584 
    585 
    586   @param This            Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
    587   @param Request         A null-terminated Unicode string in <ConfigRequest> format.
    588   @param Progress        On return, points to a character in the Request string.
    589                          Points to the string's null terminator if request was successful.
    590                          Points to the most recent '&' before the first failing name/value
    591                          pair (or the beginning of the string if the failure is in the
    592                          first name/value pair) if the request was not successful.
    593   @param Results         A null-terminated Unicode string in <ConfigAltResp> format which
    594                          has all values filled in for the names in the Request string.
    595                          String to be allocated by the called function.
    596 
    597   @retval  EFI_SUCCESS            The Results is filled with the requested values.
    598   @retval  EFI_OUT_OF_RESOURCES   Not enough memory to store the results.
    599   @retval  EFI_INVALID_PARAMETER  Request is illegal syntax, or unknown name.
    600   @retval  EFI_NOT_FOUND          Routing data doesn't match any storage in this driver.
    601 
    602 **/
    603 EFI_STATUS
    604 EFIAPI
    605 BootManagerExtractConfig (
    606   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
    607   IN  CONST EFI_STRING                       Request,
    608   OUT EFI_STRING                             *Progress,
    609   OUT EFI_STRING                             *Results
    610   )
    611 {
    612   if (Progress == NULL || Results == NULL) {
    613     return EFI_INVALID_PARAMETER;
    614   }
    615   *Progress = Request;
    616   return EFI_NOT_FOUND;
    617 }
    618 
    619 /**
    620   This function processes the results of changes in configuration.
    621 
    622 
    623   @param This            Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
    624   @param Configuration   A null-terminated Unicode string in <ConfigResp> format.
    625   @param Progress        A pointer to a string filled in with the offset of the most
    626                          recent '&' before the first failing name/value pair (or the
    627                          beginning of the string if the failure is in the first
    628                          name/value pair) or the terminating NULL if all was successful.
    629 
    630   @retval  EFI_SUCCESS            The Results is processed successfully.
    631   @retval  EFI_INVALID_PARAMETER  Configuration is NULL.
    632   @retval  EFI_NOT_FOUND          Routing data doesn't match any storage in this driver.
    633 
    634 **/
    635 EFI_STATUS
    636 EFIAPI
    637 BootManagerRouteConfig (
    638   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
    639   IN  CONST EFI_STRING                       Configuration,
    640   OUT EFI_STRING                             *Progress
    641   )
    642 {
    643   if (Configuration == NULL || Progress == NULL) {
    644     return EFI_INVALID_PARAMETER;
    645   }
    646 
    647   *Progress = Configuration;
    648 
    649   return EFI_NOT_FOUND;
    650 }
    651 
    652 /**
    653   This call back function is registered with Boot Manager formset.
    654   When user selects a boot option, this call back function will
    655   be triggered. The boot option is saved for later processing.
    656 
    657 
    658   @param This            Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
    659   @param Action          Specifies the type of action taken by the browser.
    660   @param QuestionId      A unique value which is sent to the original exporting driver
    661                          so that it can identify the type of data to expect.
    662   @param Type            The type of value for the question.
    663   @param Value           A pointer to the data being sent to the original exporting driver.
    664   @param ActionRequest   On return, points to the action requested by the callback function.
    665 
    666   @retval  EFI_SUCCESS           The callback successfully handled the action.
    667   @retval  EFI_INVALID_PARAMETER The setup browser call this function with invalid parameters.
    668 
    669 **/
    670 EFI_STATUS
    671 EFIAPI
    672 BootManagerCallback (
    673   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
    674   IN  EFI_BROWSER_ACTION                     Action,
    675   IN  EFI_QUESTION_ID                        QuestionId,
    676   IN  UINT8                                  Type,
    677   IN  EFI_IFR_TYPE_VALUE                     *Value,
    678   OUT EFI_BROWSER_ACTION_REQUEST             *ActionRequest
    679   )
    680 {
    681   EFI_BOOT_MANAGER_LOAD_OPTION *BootOption;
    682   UINTN                        BootOptionCount;
    683   EFI_INPUT_KEY                Key;
    684 
    685   if (Action == EFI_BROWSER_ACTION_FORM_OPEN) {
    686     //
    687     //Means enter the boot manager form.
    688     //Update the boot manage page,because the boot option may changed.
    689     //
    690     if (QuestionId == 0x1212){
    691       UpdateBootManager();
    692     }
    693     return EFI_SUCCESS;
    694   }
    695 
    696   if (Action != EFI_BROWSER_ACTION_CHANGED) {
    697     //
    698     // Do nothing for other UEFI Action. Only do call back when data is changed.
    699     //
    700     return EFI_UNSUPPORTED;
    701   }
    702 
    703   if ((Value == NULL) || (ActionRequest == NULL)) {
    704     return EFI_INVALID_PARAMETER;
    705   }
    706 
    707   BootOption = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
    708 
    709   //
    710   // Clear  the  screen  before.
    711   //
    712   gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
    713   gST->ConOut->ClearScreen (gST->ConOut);
    714 
    715   //
    716   // parse the selected option
    717   //
    718   BmBdsSetConsoleMode (FALSE);
    719   EfiBootManagerBoot (&BootOption[QuestionId - 1]);
    720   BmBdsSetConsoleMode (TRUE);
    721 
    722   if (EFI_ERROR (BootOption[QuestionId - 1].Status)) {
    723     gST->ConOut->OutputString (
    724                   gST->ConOut,
    725                   HiiGetString (gBootManagerPrivate.HiiHandle, STRING_TOKEN (STR_ANY_KEY_CONTINUE), NULL)
    726                   );
    727     gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
    728   }
    729 
    730   EfiBootManagerFreeLoadOptions (BootOption, BootOptionCount);
    731 
    732   return EFI_SUCCESS;
    733 }
    734 
    735 /**
    736 
    737   Install Boot Manager Menu driver.
    738 
    739   @param ImageHandle     The image handle.
    740   @param SystemTable     The system table.
    741 
    742   @retval  EFI_SUCEESS  Install Boot manager menu success.
    743   @retval  Other        Return error status.
    744 
    745 **/
    746 EFI_STATUS
    747 EFIAPI
    748 BootManagerLibConstructor (
    749   IN EFI_HANDLE                            ImageHandle,
    750   IN EFI_SYSTEM_TABLE                      *SystemTable
    751   )
    752 {
    753   EFI_STATUS                     Status;
    754 
    755   //
    756   // Install Device Path Protocol and Config Access protocol to driver handle
    757   //
    758   gBootManagerPrivate.DriverHandle = NULL;
    759   Status = gBS->InstallMultipleProtocolInterfaces (
    760                   &gBootManagerPrivate.DriverHandle,
    761                   &gEfiDevicePathProtocolGuid,
    762                   &mBootManagerHiiVendorDevicePath,
    763                   &gEfiHiiConfigAccessProtocolGuid,
    764                   &gBootManagerPrivate.ConfigAccess,
    765                   NULL
    766                   );
    767   ASSERT_EFI_ERROR (Status);
    768 
    769   //
    770   // Publish our HII data
    771   //
    772   gBootManagerPrivate.HiiHandle = HiiAddPackages (
    773                                     &mBootManagerGuid,
    774                                     gBootManagerPrivate.DriverHandle,
    775                                     BootManagerVfrBin,
    776                                     BootManagerLibStrings,
    777                                     NULL
    778                                     );
    779   ASSERT (gBootManagerPrivate.HiiHandle != NULL);
    780 
    781 
    782   return EFI_SUCCESS;
    783 }
    784 
    785 /**
    786   Unloads the application and its installed protocol.
    787 
    788   @param[in]  ImageHandle       Handle that identifies the image to be unloaded.
    789   @param[in]  SystemTable       System Table
    790 
    791   @retval EFI_SUCCESS           The image has been unloaded.
    792 **/
    793 EFI_STATUS
    794 EFIAPI
    795 BootManagerLibDestructor (
    796   IN EFI_HANDLE                            ImageHandle,
    797   IN EFI_SYSTEM_TABLE                      *SystemTable
    798   )
    799 {
    800   EFI_STATUS    Status;
    801 
    802   Status = gBS->UninstallMultipleProtocolInterfaces (
    803                   gBootManagerPrivate.DriverHandle,
    804                   &gEfiDevicePathProtocolGuid,
    805                   &mBootManagerHiiVendorDevicePath,
    806                   &gEfiHiiConfigAccessProtocolGuid,
    807                   &gBootManagerPrivate.ConfigAccess,
    808                   NULL
    809                   );
    810   ASSERT_EFI_ERROR (Status);
    811 
    812   HiiRemovePackages (gBootManagerPrivate.HiiHandle);
    813 
    814   return EFI_SUCCESS;
    815 }
    816 
    817