Home | History | Annotate | Download | only in BootMngr
      1 /** @file
      2   The platform boot manager reference implementation
      3 
      4 Copyright (c) 2004 - 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 "BootManager.h"
     16 
     17 UINT16             mKeyInput;
     18 LIST_ENTRY         mBootOptionsList;
     19 BDS_COMMON_OPTION  *gOption;
     20 CHAR16             *mDeviceTypeStr[] = {
     21   L"Legacy BEV",
     22   L"Legacy Floppy",
     23   L"Legacy Hard Drive",
     24   L"Legacy CD ROM",
     25   L"Legacy PCMCIA",
     26   L"Legacy USB",
     27   L"Legacy Embedded Network",
     28   L"Legacy Unknown Device"
     29 };
     30 
     31 
     32 HII_VENDOR_DEVICE_PATH  mBootManagerHiiVendorDevicePath = {
     33   {
     34     {
     35       HARDWARE_DEVICE_PATH,
     36       HW_VENDOR_DP,
     37       {
     38         (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
     39         (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
     40       }
     41     },
     42     BOOT_MANAGER_FORMSET_GUID
     43   },
     44   {
     45     END_DEVICE_PATH_TYPE,
     46     END_ENTIRE_DEVICE_PATH_SUBTYPE,
     47     {
     48       (UINT8) (END_DEVICE_PATH_LENGTH),
     49       (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
     50     }
     51   }
     52 };
     53 
     54 BOOT_MANAGER_CALLBACK_DATA  gBootManagerPrivate = {
     55   BOOT_MANAGER_CALLBACK_DATA_SIGNATURE,
     56   NULL,
     57   NULL,
     58   {
     59     FakeExtractConfig,
     60     FakeRouteConfig,
     61     BootManagerCallback
     62   }
     63 };
     64 
     65 /**
     66   This call back function is registered with Boot Manager formset.
     67   When user selects a boot option, this call back function will
     68   be triggered. The boot option is saved for later processing.
     69 
     70 
     71   @param This            Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
     72   @param Action          Specifies the type of action taken by the browser.
     73   @param QuestionId      A unique value which is sent to the original exporting driver
     74                          so that it can identify the type of data to expect.
     75   @param Type            The type of value for the question.
     76   @param Value           A pointer to the data being sent to the original exporting driver.
     77   @param ActionRequest   On return, points to the action requested by the callback function.
     78 
     79   @retval  EFI_SUCCESS           The callback successfully handled the action.
     80   @retval  EFI_INVALID_PARAMETER The setup browser call this function with invalid parameters.
     81 
     82 **/
     83 EFI_STATUS
     84 EFIAPI
     85 BootManagerCallback (
     86   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
     87   IN  EFI_BROWSER_ACTION                     Action,
     88   IN  EFI_QUESTION_ID                        QuestionId,
     89   IN  UINT8                                  Type,
     90   IN  EFI_IFR_TYPE_VALUE                     *Value,
     91   OUT EFI_BROWSER_ACTION_REQUEST             *ActionRequest
     92   )
     93 {
     94   BDS_COMMON_OPTION       *Option;
     95   LIST_ENTRY              *Link;
     96   UINT16                  KeyCount;
     97 
     98   if (Action == EFI_BROWSER_ACTION_CHANGED) {
     99     if ((Value == NULL) || (ActionRequest == NULL)) {
    100       return EFI_INVALID_PARAMETER;
    101     }
    102 
    103     //
    104     // Initialize the key count
    105     //
    106     KeyCount = 0;
    107 
    108     for (Link = GetFirstNode (&mBootOptionsList); !IsNull (&mBootOptionsList, Link); Link = GetNextNode (&mBootOptionsList, Link)) {
    109       Option = CR (Link, BDS_COMMON_OPTION, Link, BDS_LOAD_OPTION_SIGNATURE);
    110 
    111       KeyCount++;
    112 
    113       gOption = Option;
    114 
    115       //
    116       // Is this device the one chosen?
    117       //
    118       if (KeyCount == QuestionId) {
    119         //
    120         // Assigning the returned Key to a global allows the original routine to know what was chosen
    121         //
    122         mKeyInput = QuestionId;
    123 
    124         //
    125         // Request to exit SendForm(), so that we could boot the selected option
    126         //
    127         *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;
    128         break;
    129       }
    130     }
    131 
    132     return EFI_SUCCESS;
    133   }
    134 
    135   //
    136   // All other action return unsupported.
    137   //
    138   return EFI_UNSUPPORTED;
    139 }
    140 
    141 /**
    142 
    143   Registers HII packages for the Boot Manger to HII Database.
    144   It also registers the browser call back function.
    145 
    146   @retval  EFI_SUCCESS           HII packages for the Boot Manager were registered successfully.
    147   @retval  EFI_OUT_OF_RESOURCES  HII packages for the Boot Manager failed to be registered.
    148 
    149 **/
    150 EFI_STATUS
    151 InitializeBootManager (
    152   VOID
    153   )
    154 {
    155   EFI_STATUS                  Status;
    156 
    157   //
    158   // Install Device Path Protocol and Config Access protocol to driver handle
    159   //
    160   Status = gBS->InstallMultipleProtocolInterfaces (
    161                   &gBootManagerPrivate.DriverHandle,
    162                   &gEfiDevicePathProtocolGuid,
    163                   &mBootManagerHiiVendorDevicePath,
    164                   &gEfiHiiConfigAccessProtocolGuid,
    165                   &gBootManagerPrivate.ConfigAccess,
    166                   NULL
    167                   );
    168   ASSERT_EFI_ERROR (Status);
    169 
    170   //
    171   // Publish our HII data
    172   //
    173   gBootManagerPrivate.HiiHandle = HiiAddPackages (
    174                                     &gBootManagerFormSetGuid,
    175                                     gBootManagerPrivate.DriverHandle,
    176                                     BootManagerVfrBin,
    177                                     BdsDxeStrings,
    178                                     NULL
    179                                     );
    180   if (gBootManagerPrivate.HiiHandle == NULL) {
    181     Status = EFI_OUT_OF_RESOURCES;
    182   } else {
    183     Status = EFI_SUCCESS;
    184   }
    185   return Status;
    186 }
    187 
    188 /**
    189   This function invokes Boot Manager. If all devices have not a chance to be connected,
    190   the connect all will be triggered. It then enumerate all boot options. If
    191   a boot option from the Boot Manager page is selected, Boot Manager will boot
    192   from this boot option.
    193 
    194 **/
    195 VOID
    196 CallBootManager (
    197   VOID
    198   )
    199 {
    200   EFI_STATUS                  Status;
    201   BDS_COMMON_OPTION           *Option;
    202   LIST_ENTRY                  *Link;
    203   CHAR16                      *ExitData;
    204   UINTN                       ExitDataSize;
    205   EFI_STRING_ID               Token;
    206   EFI_INPUT_KEY               Key;
    207   CHAR16                      *HelpString;
    208   UINTN                       HelpSize;
    209   EFI_STRING_ID               HelpToken;
    210   UINT16                      *TempStr;
    211   EFI_HII_HANDLE              HiiHandle;
    212   EFI_BROWSER_ACTION_REQUEST  ActionRequest;
    213   VOID                        *StartOpCodeHandle;
    214   VOID                        *EndOpCodeHandle;
    215   EFI_IFR_GUID_LABEL          *StartLabel;
    216   EFI_IFR_GUID_LABEL          *EndLabel;
    217   UINT16                      DeviceType;
    218   BOOLEAN                     IsLegacyOption;
    219   BOOLEAN                     NeedEndOp;
    220 
    221   DeviceType = (UINT16) -1;
    222   gOption    = NULL;
    223   InitializeListHead (&mBootOptionsList);
    224 
    225   //
    226   // Connect all prior to entering the platform setup menu.
    227   //
    228   if (!gConnectAllHappened) {
    229     BdsLibConnectAllDriversToAllControllers ();
    230     gConnectAllHappened = TRUE;
    231   }
    232 
    233   BdsLibEnumerateAllBootOption (&mBootOptionsList);
    234 
    235   //
    236   // Group the legacy boot options for the same device type
    237   //
    238   GroupMultipleLegacyBootOption4SameType ();
    239 
    240   InitializeListHead (&mBootOptionsList);
    241   BdsLibBuildOptionFromVar (&mBootOptionsList, L"BootOrder");
    242 
    243   HiiHandle = gBootManagerPrivate.HiiHandle;
    244 
    245   //
    246   // Allocate space for creation of UpdateData Buffer
    247   //
    248   StartOpCodeHandle = HiiAllocateOpCodeHandle ();
    249   ASSERT (StartOpCodeHandle != NULL);
    250 
    251   EndOpCodeHandle = HiiAllocateOpCodeHandle ();
    252   ASSERT (EndOpCodeHandle != NULL);
    253 
    254   //
    255   // Create Hii Extend Label OpCode as the start opcode
    256   //
    257   StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
    258   StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
    259   StartLabel->Number       = LABEL_BOOT_OPTION;
    260 
    261   //
    262   // Create Hii Extend Label OpCode as the end opcode
    263   //
    264   EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
    265   EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
    266   EndLabel->Number       = LABEL_BOOT_OPTION_END;
    267 
    268   mKeyInput = 0;
    269   NeedEndOp = FALSE;
    270   for (Link = GetFirstNode (&mBootOptionsList); !IsNull (&mBootOptionsList, Link); Link = GetNextNode (&mBootOptionsList, Link)) {
    271     Option = CR (Link, BDS_COMMON_OPTION, Link, BDS_LOAD_OPTION_SIGNATURE);
    272 
    273     //
    274     // At this stage we are creating a menu entry, thus the Keys are reproduceable
    275     //
    276     mKeyInput++;
    277 
    278     //
    279     // Don't display the hidden/inactive boot option
    280     //
    281     if (((Option->Attribute & LOAD_OPTION_HIDDEN) != 0) || ((Option->Attribute & LOAD_OPTION_ACTIVE) == 0)) {
    282       continue;
    283     }
    284 
    285     //
    286     // Group the legacy boot option in the sub title created dynamically
    287     //
    288     IsLegacyOption = (BOOLEAN) (
    289                        (DevicePathType (Option->DevicePath) == BBS_DEVICE_PATH) &&
    290                        (DevicePathSubType (Option->DevicePath) == BBS_BBS_DP)
    291                        );
    292 
    293     if (!IsLegacyOption && NeedEndOp) {
    294       NeedEndOp = FALSE;
    295       HiiCreateEndOpCode (StartOpCodeHandle);
    296     }
    297 
    298     if (IsLegacyOption && DeviceType != ((BBS_BBS_DEVICE_PATH *) Option->DevicePath)->DeviceType) {
    299       if (NeedEndOp) {
    300         HiiCreateEndOpCode (StartOpCodeHandle);
    301       }
    302 
    303       DeviceType = ((BBS_BBS_DEVICE_PATH *) Option->DevicePath)->DeviceType;
    304       Token      = HiiSetString (
    305                      HiiHandle,
    306                      0,
    307                      mDeviceTypeStr[
    308                        MIN (DeviceType & 0xF, ARRAY_SIZE (mDeviceTypeStr) - 1)
    309                        ],
    310                      NULL
    311                      );
    312       HiiCreateSubTitleOpCode (StartOpCodeHandle, Token, 0, 0, 1);
    313       NeedEndOp = TRUE;
    314     }
    315 
    316     ASSERT (Option->Description != NULL);
    317 
    318     Token = HiiSetString (HiiHandle, 0, Option->Description, NULL);
    319 
    320     TempStr = DevicePathToStr (Option->DevicePath);
    321     HelpSize = StrSize (TempStr) + StrSize (L"Device Path : ");
    322     HelpString = AllocateZeroPool (HelpSize);
    323     ASSERT (HelpString != NULL);
    324     StrCatS (HelpString, HelpSize / sizeof (CHAR16), L"Device Path : ");
    325     StrCatS (HelpString, HelpSize / sizeof (CHAR16), TempStr);
    326 
    327     HelpToken = HiiSetString (HiiHandle, 0, HelpString, NULL);
    328 
    329     HiiCreateActionOpCode (
    330       StartOpCodeHandle,
    331       mKeyInput,
    332       Token,
    333       HelpToken,
    334       EFI_IFR_FLAG_CALLBACK,
    335       0
    336       );
    337   }
    338 
    339   if (NeedEndOp) {
    340     HiiCreateEndOpCode (StartOpCodeHandle);
    341   }
    342 
    343   HiiUpdateForm (
    344     HiiHandle,
    345     &gBootManagerFormSetGuid,
    346     BOOT_MANAGER_FORM_ID,
    347     StartOpCodeHandle,
    348     EndOpCodeHandle
    349     );
    350 
    351   HiiFreeOpCodeHandle (StartOpCodeHandle);
    352   HiiFreeOpCodeHandle (EndOpCodeHandle);
    353 
    354   ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
    355   Status = gFormBrowser2->SendForm (
    356                            gFormBrowser2,
    357                            &HiiHandle,
    358                            1,
    359                            &gBootManagerFormSetGuid,
    360                            0,
    361                            NULL,
    362                            &ActionRequest
    363                            );
    364   if (ActionRequest == EFI_BROWSER_ACTION_REQUEST_RESET) {
    365     EnableResetRequired ();
    366   }
    367 
    368   if (gOption == NULL) {
    369     return ;
    370   }
    371 
    372   //
    373   // Will leave browser, check any reset required change is applied? if yes, reset system
    374   //
    375   SetupResetReminder ();
    376 
    377   //
    378   // Restore to original mode before launching boot option.
    379   //
    380   BdsSetConsoleMode (FALSE);
    381 
    382   //
    383   // parse the selected option
    384   //
    385   Status = BdsLibBootViaBootOption (gOption, gOption->DevicePath, &ExitDataSize, &ExitData);
    386 
    387   if (!EFI_ERROR (Status)) {
    388     gOption->StatusString = GetStringById (STRING_TOKEN (STR_BOOT_SUCCEEDED));
    389     PlatformBdsBootSuccess (gOption);
    390   } else {
    391     gOption->StatusString = GetStringById (STRING_TOKEN (STR_BOOT_FAILED));
    392     PlatformBdsBootFail (gOption, Status, ExitData, ExitDataSize);
    393     gST->ConOut->OutputString (
    394                   gST->ConOut,
    395                   GetStringById (STRING_TOKEN (STR_ANY_KEY_CONTINUE))
    396                   );
    397     gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
    398   }
    399 }
    400