Cc: Jeff Fan <jeff.fan@intel.com> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Laszlo Ersek <lersek@redhat.com> Reviewed-by: Jeff Fan <jeff.fan@intel.com> Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>
		
			
				
	
	
		
			400 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			400 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  The platform boot manager reference implementation
 | 
						|
 | 
						|
Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>
 | 
						|
This program and the accompanying materials
 | 
						|
are licensed and made available under the terms and conditions of the BSD License
 | 
						|
which accompanies this distribution.  The full text of the license may be found at
 | 
						|
http://opensource.org/licenses/bsd-license.php
 | 
						|
 | 
						|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | 
						|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#include "BootManager.h"
 | 
						|
 | 
						|
UINT16             mKeyInput;
 | 
						|
LIST_ENTRY         mBootOptionsList;
 | 
						|
BDS_COMMON_OPTION  *gOption;
 | 
						|
CHAR16             *mDeviceTypeStr[] = {
 | 
						|
  L"Legacy BEV",
 | 
						|
  L"Legacy Floppy",
 | 
						|
  L"Legacy Hard Drive",
 | 
						|
  L"Legacy CD ROM",
 | 
						|
  L"Legacy PCMCIA",
 | 
						|
  L"Legacy USB",
 | 
						|
  L"Legacy Embedded Network",
 | 
						|
  L"Legacy Unknown Device"
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
HII_VENDOR_DEVICE_PATH  mBootManagerHiiVendorDevicePath = {
 | 
						|
  {
 | 
						|
    {
 | 
						|
      HARDWARE_DEVICE_PATH,
 | 
						|
      HW_VENDOR_DP,
 | 
						|
      {
 | 
						|
        (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
 | 
						|
        (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
 | 
						|
      }
 | 
						|
    },
 | 
						|
    BOOT_MANAGER_FORMSET_GUID
 | 
						|
  },
 | 
						|
  {
 | 
						|
    END_DEVICE_PATH_TYPE,
 | 
						|
    END_ENTIRE_DEVICE_PATH_SUBTYPE,
 | 
						|
    { 
 | 
						|
      (UINT8) (END_DEVICE_PATH_LENGTH),
 | 
						|
      (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
 | 
						|
    }
 | 
						|
  }
 | 
						|
};
 | 
						|
 | 
						|
BOOT_MANAGER_CALLBACK_DATA  gBootManagerPrivate = {
 | 
						|
  BOOT_MANAGER_CALLBACK_DATA_SIGNATURE,
 | 
						|
  NULL,
 | 
						|
  NULL,
 | 
						|
  {
 | 
						|
    FakeExtractConfig,
 | 
						|
    FakeRouteConfig,
 | 
						|
    BootManagerCallback
 | 
						|
  }
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
  This call back function is registered with Boot Manager formset.
 | 
						|
  When user selects a boot option, this call back function will
 | 
						|
  be triggered. The boot option is saved for later processing.
 | 
						|
 | 
						|
 | 
						|
  @param This            Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
 | 
						|
  @param Action          Specifies the type of action taken by the browser.
 | 
						|
  @param QuestionId      A unique value which is sent to the original exporting driver
 | 
						|
                         so that it can identify the type of data to expect.
 | 
						|
  @param Type            The type of value for the question.
 | 
						|
  @param Value           A pointer to the data being sent to the original exporting driver.
 | 
						|
  @param ActionRequest   On return, points to the action requested by the callback function.
 | 
						|
 | 
						|
  @retval  EFI_SUCCESS           The callback successfully handled the action.
 | 
						|
  @retval  EFI_INVALID_PARAMETER The setup browser call this function with invalid parameters.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
BootManagerCallback (
 | 
						|
  IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
 | 
						|
  IN  EFI_BROWSER_ACTION                     Action,
 | 
						|
  IN  EFI_QUESTION_ID                        QuestionId,
 | 
						|
  IN  UINT8                                  Type,
 | 
						|
  IN  EFI_IFR_TYPE_VALUE                     *Value,
 | 
						|
  OUT EFI_BROWSER_ACTION_REQUEST             *ActionRequest
 | 
						|
  )
 | 
						|
{
 | 
						|
  BDS_COMMON_OPTION       *Option;
 | 
						|
  LIST_ENTRY              *Link;
 | 
						|
  UINT16                  KeyCount;
 | 
						|
 | 
						|
  if (Action == EFI_BROWSER_ACTION_CHANGED) {
 | 
						|
    if ((Value == NULL) || (ActionRequest == NULL)) {
 | 
						|
      return EFI_INVALID_PARAMETER;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Initialize the key count
 | 
						|
    //
 | 
						|
    KeyCount = 0;
 | 
						|
 | 
						|
    for (Link = GetFirstNode (&mBootOptionsList); !IsNull (&mBootOptionsList, Link); Link = GetNextNode (&mBootOptionsList, Link)) {
 | 
						|
      Option = CR (Link, BDS_COMMON_OPTION, Link, BDS_LOAD_OPTION_SIGNATURE);
 | 
						|
 | 
						|
      KeyCount++;
 | 
						|
 | 
						|
      gOption = Option;
 | 
						|
 | 
						|
      //
 | 
						|
      // Is this device the one chosen?
 | 
						|
      //
 | 
						|
      if (KeyCount == QuestionId) {
 | 
						|
        //
 | 
						|
        // Assigning the returned Key to a global allows the original routine to know what was chosen
 | 
						|
        //
 | 
						|
        mKeyInput = QuestionId;
 | 
						|
 | 
						|
        //
 | 
						|
        // Request to exit SendForm(), so that we could boot the selected option
 | 
						|
        //
 | 
						|
        *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;
 | 
						|
        break;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // All other action return unsupported.
 | 
						|
  //
 | 
						|
  return EFI_UNSUPPORTED;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 | 
						|
  Registers HII packages for the Boot Manger to HII Database.
 | 
						|
  It also registers the browser call back function.
 | 
						|
 | 
						|
  @retval  EFI_SUCCESS           HII packages for the Boot Manager were registered successfully.
 | 
						|
  @retval  EFI_OUT_OF_RESOURCES  HII packages for the Boot Manager failed to be registered.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
InitializeBootManager (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                  Status;
 | 
						|
 | 
						|
  //
 | 
						|
  // Install Device Path Protocol and Config Access protocol to driver handle
 | 
						|
  //
 | 
						|
  Status = gBS->InstallMultipleProtocolInterfaces (
 | 
						|
                  &gBootManagerPrivate.DriverHandle,
 | 
						|
                  &gEfiDevicePathProtocolGuid,
 | 
						|
                  &mBootManagerHiiVendorDevicePath,
 | 
						|
                  &gEfiHiiConfigAccessProtocolGuid,
 | 
						|
                  &gBootManagerPrivate.ConfigAccess,
 | 
						|
                  NULL
 | 
						|
                  );
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
 | 
						|
  //
 | 
						|
  // Publish our HII data
 | 
						|
  //
 | 
						|
  gBootManagerPrivate.HiiHandle = HiiAddPackages (
 | 
						|
                                    &gBootManagerFormSetGuid,
 | 
						|
                                    gBootManagerPrivate.DriverHandle,
 | 
						|
                                    BootManagerVfrBin,
 | 
						|
                                    BdsDxeStrings,
 | 
						|
                                    NULL
 | 
						|
                                    );
 | 
						|
  if (gBootManagerPrivate.HiiHandle == NULL) {
 | 
						|
    Status = EFI_OUT_OF_RESOURCES;
 | 
						|
  } else {
 | 
						|
    Status = EFI_SUCCESS;
 | 
						|
  }
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This function invokes Boot Manager. If all devices have not a chance to be connected,
 | 
						|
  the connect all will be triggered. It then enumerate all boot options. If 
 | 
						|
  a boot option from the Boot Manager page is selected, Boot Manager will boot
 | 
						|
  from this boot option.
 | 
						|
  
 | 
						|
**/
 | 
						|
VOID
 | 
						|
CallBootManager (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                  Status;
 | 
						|
  BDS_COMMON_OPTION           *Option;
 | 
						|
  LIST_ENTRY                  *Link;
 | 
						|
  CHAR16                      *ExitData;
 | 
						|
  UINTN                       ExitDataSize;
 | 
						|
  EFI_STRING_ID               Token;
 | 
						|
  EFI_INPUT_KEY               Key;
 | 
						|
  CHAR16                      *HelpString;
 | 
						|
  UINTN                       HelpSize;
 | 
						|
  EFI_STRING_ID               HelpToken;
 | 
						|
  UINT16                      *TempStr;
 | 
						|
  EFI_HII_HANDLE              HiiHandle;
 | 
						|
  EFI_BROWSER_ACTION_REQUEST  ActionRequest;
 | 
						|
  VOID                        *StartOpCodeHandle;
 | 
						|
  VOID                        *EndOpCodeHandle;
 | 
						|
  EFI_IFR_GUID_LABEL          *StartLabel;
 | 
						|
  EFI_IFR_GUID_LABEL          *EndLabel;
 | 
						|
  UINT16                      DeviceType;
 | 
						|
  BOOLEAN                     IsLegacyOption;
 | 
						|
  BOOLEAN                     NeedEndOp;
 | 
						|
 | 
						|
  DeviceType = (UINT16) -1;
 | 
						|
  gOption    = NULL;
 | 
						|
  InitializeListHead (&mBootOptionsList);
 | 
						|
 | 
						|
  //
 | 
						|
  // Connect all prior to entering the platform setup menu.
 | 
						|
  //
 | 
						|
  if (!gConnectAllHappened) {
 | 
						|
    BdsLibConnectAllDriversToAllControllers ();
 | 
						|
    gConnectAllHappened = TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  BdsLibEnumerateAllBootOption (&mBootOptionsList);
 | 
						|
 | 
						|
  //
 | 
						|
  // Group the legacy boot options for the same device type
 | 
						|
  //
 | 
						|
  GroupMultipleLegacyBootOption4SameType ();
 | 
						|
 | 
						|
  InitializeListHead (&mBootOptionsList);
 | 
						|
  BdsLibBuildOptionFromVar (&mBootOptionsList, L"BootOrder");
 | 
						|
 | 
						|
  HiiHandle = gBootManagerPrivate.HiiHandle;
 | 
						|
 | 
						|
  //
 | 
						|
  // Allocate space for creation of UpdateData Buffer
 | 
						|
  //
 | 
						|
  StartOpCodeHandle = HiiAllocateOpCodeHandle ();
 | 
						|
  ASSERT (StartOpCodeHandle != NULL);
 | 
						|
 | 
						|
  EndOpCodeHandle = HiiAllocateOpCodeHandle ();
 | 
						|
  ASSERT (EndOpCodeHandle != NULL);
 | 
						|
 | 
						|
  //
 | 
						|
  // Create Hii Extend Label OpCode as the start opcode
 | 
						|
  //
 | 
						|
  StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
 | 
						|
  StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
 | 
						|
  StartLabel->Number       = LABEL_BOOT_OPTION;
 | 
						|
 | 
						|
  //
 | 
						|
  // Create Hii Extend Label OpCode as the end opcode
 | 
						|
  //
 | 
						|
  EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
 | 
						|
  EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
 | 
						|
  EndLabel->Number       = LABEL_BOOT_OPTION_END;
 | 
						|
 | 
						|
  mKeyInput = 0;
 | 
						|
  NeedEndOp = FALSE;
 | 
						|
  for (Link = GetFirstNode (&mBootOptionsList); !IsNull (&mBootOptionsList, Link); Link = GetNextNode (&mBootOptionsList, Link)) {
 | 
						|
    Option = CR (Link, BDS_COMMON_OPTION, Link, BDS_LOAD_OPTION_SIGNATURE);
 | 
						|
 | 
						|
    //
 | 
						|
    // At this stage we are creating a menu entry, thus the Keys are reproduceable
 | 
						|
    //
 | 
						|
    mKeyInput++;
 | 
						|
 | 
						|
    //
 | 
						|
    // Don't display the hidden/inactive boot option
 | 
						|
    //
 | 
						|
    if (((Option->Attribute & LOAD_OPTION_HIDDEN) != 0) || ((Option->Attribute & LOAD_OPTION_ACTIVE) == 0)) {
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Group the legacy boot option in the sub title created dynamically
 | 
						|
    //
 | 
						|
    IsLegacyOption = (BOOLEAN) (
 | 
						|
                       (DevicePathType (Option->DevicePath) == BBS_DEVICE_PATH) &&
 | 
						|
                       (DevicePathSubType (Option->DevicePath) == BBS_BBS_DP)
 | 
						|
                       );
 | 
						|
 | 
						|
    if (!IsLegacyOption && NeedEndOp) {
 | 
						|
      NeedEndOp = FALSE;
 | 
						|
      HiiCreateEndOpCode (StartOpCodeHandle);
 | 
						|
    }
 | 
						|
    
 | 
						|
    if (IsLegacyOption && DeviceType != ((BBS_BBS_DEVICE_PATH *) Option->DevicePath)->DeviceType) {
 | 
						|
      if (NeedEndOp) {
 | 
						|
        HiiCreateEndOpCode (StartOpCodeHandle);
 | 
						|
      }
 | 
						|
 | 
						|
      DeviceType = ((BBS_BBS_DEVICE_PATH *) Option->DevicePath)->DeviceType;
 | 
						|
      Token      = HiiSetString (
 | 
						|
                     HiiHandle,
 | 
						|
                     0,
 | 
						|
                     mDeviceTypeStr[
 | 
						|
                       MIN (DeviceType & 0xF, ARRAY_SIZE (mDeviceTypeStr) - 1)
 | 
						|
                       ],
 | 
						|
                     NULL
 | 
						|
                     );
 | 
						|
      HiiCreateSubTitleOpCode (StartOpCodeHandle, Token, 0, 0, 1);
 | 
						|
      NeedEndOp = TRUE;
 | 
						|
    }
 | 
						|
 | 
						|
    ASSERT (Option->Description != NULL);
 | 
						|
    
 | 
						|
    Token = HiiSetString (HiiHandle, 0, Option->Description, NULL);
 | 
						|
 | 
						|
    TempStr = DevicePathToStr (Option->DevicePath);
 | 
						|
    HelpSize = StrSize (TempStr) + StrSize (L"Device Path : ");
 | 
						|
    HelpString = AllocateZeroPool (HelpSize);
 | 
						|
    ASSERT (HelpString != NULL);
 | 
						|
    StrCatS (HelpString, HelpSize / sizeof (CHAR16), L"Device Path : ");
 | 
						|
    StrCatS (HelpString, HelpSize / sizeof (CHAR16), TempStr);
 | 
						|
 | 
						|
    HelpToken = HiiSetString (HiiHandle, 0, HelpString, NULL);
 | 
						|
 | 
						|
    HiiCreateActionOpCode (
 | 
						|
      StartOpCodeHandle,
 | 
						|
      mKeyInput,
 | 
						|
      Token,
 | 
						|
      HelpToken,
 | 
						|
      EFI_IFR_FLAG_CALLBACK,
 | 
						|
      0
 | 
						|
      );
 | 
						|
  }
 | 
						|
 | 
						|
  if (NeedEndOp) {
 | 
						|
    HiiCreateEndOpCode (StartOpCodeHandle);
 | 
						|
  }
 | 
						|
 | 
						|
  HiiUpdateForm (
 | 
						|
    HiiHandle,
 | 
						|
    &gBootManagerFormSetGuid,
 | 
						|
    BOOT_MANAGER_FORM_ID,
 | 
						|
    StartOpCodeHandle,
 | 
						|
    EndOpCodeHandle
 | 
						|
    );
 | 
						|
 | 
						|
  HiiFreeOpCodeHandle (StartOpCodeHandle);
 | 
						|
  HiiFreeOpCodeHandle (EndOpCodeHandle);
 | 
						|
 | 
						|
  ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
 | 
						|
  Status = gFormBrowser2->SendForm (
 | 
						|
                           gFormBrowser2,
 | 
						|
                           &HiiHandle,
 | 
						|
                           1,
 | 
						|
                           &gBootManagerFormSetGuid,
 | 
						|
                           0,
 | 
						|
                           NULL,
 | 
						|
                           &ActionRequest
 | 
						|
                           );
 | 
						|
  if (ActionRequest == EFI_BROWSER_ACTION_REQUEST_RESET) {
 | 
						|
    EnableResetRequired ();
 | 
						|
  }
 | 
						|
 | 
						|
  if (gOption == NULL) {
 | 
						|
    return ;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Will leave browser, check any reset required change is applied? if yes, reset system
 | 
						|
  //
 | 
						|
  SetupResetReminder ();
 | 
						|
 | 
						|
  //
 | 
						|
  // Restore to original mode before launching boot option.
 | 
						|
  //
 | 
						|
  BdsSetConsoleMode (FALSE);
 | 
						|
 | 
						|
  //
 | 
						|
  // parse the selected option
 | 
						|
  //
 | 
						|
  Status = BdsLibBootViaBootOption (gOption, gOption->DevicePath, &ExitDataSize, &ExitData);
 | 
						|
 | 
						|
  if (!EFI_ERROR (Status)) {
 | 
						|
    gOption->StatusString = GetStringById (STRING_TOKEN (STR_BOOT_SUCCEEDED));
 | 
						|
    PlatformBdsBootSuccess (gOption);
 | 
						|
  } else {
 | 
						|
    gOption->StatusString = GetStringById (STRING_TOKEN (STR_BOOT_FAILED));
 | 
						|
    PlatformBdsBootFail (gOption, Status, ExitData, ExitDataSize);
 | 
						|
    gST->ConOut->OutputString (
 | 
						|
                  gST->ConOut,
 | 
						|
                  GetStringById (STRING_TOKEN (STR_ANY_KEY_CONTINUE))
 | 
						|
                  );
 | 
						|
    gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
 | 
						|
  }
 | 
						|
}
 |