Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ruiyu Ni <ruiyu.ni@intel.com> Reviewed-by: Eric Dong <eric.dong@intel.com> Reviewed-by: Sunny Wang <sunnywang@hpe.com>
		
			
				
	
	
		
			1337 lines
		
	
	
		
			42 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1337 lines
		
	
	
		
			42 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  Load option library functions which relate with creating and processing load options.
 | 
						|
 | 
						|
Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.<BR>
 | 
						|
(C) Copyright 2015-2016 Hewlett Packard Enterprise Development LP<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 "InternalBm.h"
 | 
						|
 | 
						|
GLOBAL_REMOVE_IF_UNREFERENCED
 | 
						|
  CHAR16 *mBmLoadOptionName[] = {
 | 
						|
    L"Driver",
 | 
						|
    L"SysPrep",
 | 
						|
    L"Boot",
 | 
						|
    L"PlatformRecovery"
 | 
						|
  };
 | 
						|
 | 
						|
GLOBAL_REMOVE_IF_UNREFERENCED
 | 
						|
  CHAR16 *mBmLoadOptionOrderName[] = {
 | 
						|
    EFI_DRIVER_ORDER_VARIABLE_NAME,
 | 
						|
    EFI_SYS_PREP_ORDER_VARIABLE_NAME,
 | 
						|
    EFI_BOOT_ORDER_VARIABLE_NAME,
 | 
						|
    NULL  // PlatformRecovery#### doesn't have associated *Order variable
 | 
						|
  };
 | 
						|
 | 
						|
/**
 | 
						|
  Call Visitor function for each variable in variable storage.
 | 
						|
 | 
						|
  @param Visitor  Visitor function.
 | 
						|
  @param Context  The context passed to Visitor function.
 | 
						|
**/
 | 
						|
VOID
 | 
						|
BmForEachVariable (
 | 
						|
  BM_VARIABLE_VISITOR         Visitor,
 | 
						|
  VOID                        *Context
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                  Status;
 | 
						|
  CHAR16                      *Name;
 | 
						|
  EFI_GUID                    Guid;
 | 
						|
  UINTN                       NameSize;
 | 
						|
  UINTN                       NewNameSize;
 | 
						|
 | 
						|
  NameSize = sizeof (CHAR16);
 | 
						|
  Name = AllocateZeroPool (NameSize);
 | 
						|
  ASSERT (Name != NULL);
 | 
						|
  while (TRUE) {
 | 
						|
    NewNameSize = NameSize;
 | 
						|
    Status = gRT->GetNextVariableName (&NewNameSize, Name, &Guid);
 | 
						|
    if (Status == EFI_BUFFER_TOO_SMALL) {
 | 
						|
      Name = ReallocatePool (NameSize, NewNameSize, Name);
 | 
						|
      ASSERT (Name != NULL);
 | 
						|
      Status = gRT->GetNextVariableName (&NewNameSize, Name, &Guid);
 | 
						|
      NameSize = NewNameSize;
 | 
						|
    }
 | 
						|
 | 
						|
    if (Status == EFI_NOT_FOUND) {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    ASSERT_EFI_ERROR (Status);
 | 
						|
 | 
						|
    Visitor (Name, &Guid, Context);
 | 
						|
  }
 | 
						|
 | 
						|
  FreePool (Name);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Get the Option Number that wasn't used.
 | 
						|
 | 
						|
  @param  LoadOptionType      The load option type.
 | 
						|
  @param  FreeOptionNumber    Return the minimal free option number.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The option number is found and will be returned.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES  There is no free option number that can be used.
 | 
						|
  @retval EFI_INVALID_PARAMETER FreeOptionNumber is NULL
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
BmGetFreeOptionNumber (
 | 
						|
  IN  EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType,
 | 
						|
  OUT UINT16                            *FreeOptionNumber
 | 
						|
  )
 | 
						|
{
 | 
						|
  
 | 
						|
  UINTN         OptionNumber;
 | 
						|
  UINTN         Index;
 | 
						|
  UINT16        *OptionOrder;
 | 
						|
  UINTN         OptionOrderSize;
 | 
						|
  UINT16        *BootNext;
 | 
						|
 | 
						|
  ASSERT (FreeOptionNumber != NULL);
 | 
						|
  ASSERT (LoadOptionType == LoadOptionTypeDriver || 
 | 
						|
          LoadOptionType == LoadOptionTypeBoot ||
 | 
						|
          LoadOptionType == LoadOptionTypeSysPrep);
 | 
						|
 | 
						|
  GetEfiGlobalVariable2 (mBmLoadOptionOrderName[LoadOptionType], (VOID **) &OptionOrder, &OptionOrderSize);
 | 
						|
  ASSERT ((OptionOrder != NULL && OptionOrderSize != 0) || (OptionOrder == NULL && OptionOrderSize == 0));
 | 
						|
 | 
						|
  BootNext = NULL;
 | 
						|
  if (LoadOptionType == LoadOptionTypeBoot) {
 | 
						|
    GetEfiGlobalVariable2 (L"BootNext", (VOID**) &BootNext, NULL);
 | 
						|
  }
 | 
						|
 | 
						|
  for (OptionNumber = 0; 
 | 
						|
       OptionNumber < OptionOrderSize / sizeof (UINT16)
 | 
						|
                    + ((BootNext != NULL) ? 1 : 0); 
 | 
						|
       OptionNumber++
 | 
						|
       ) {
 | 
						|
    //
 | 
						|
    // Search in OptionOrder whether the OptionNumber exists
 | 
						|
    //
 | 
						|
    for (Index = 0; Index < OptionOrderSize / sizeof (UINT16); Index++) {
 | 
						|
      if (OptionNumber == OptionOrder[Index]) {
 | 
						|
        break;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // We didn't find it in the ****Order array and it doesn't equal to BootNext 
 | 
						|
    // Otherwise, OptionNumber equals to OptionOrderSize / sizeof (UINT16) + 1
 | 
						|
    //
 | 
						|
    if ((Index == OptionOrderSize / sizeof (UINT16)) && 
 | 
						|
        ((BootNext == NULL) || (OptionNumber != *BootNext))
 | 
						|
        ) {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  if (OptionOrder != NULL) {
 | 
						|
    FreePool (OptionOrder);
 | 
						|
  }
 | 
						|
 | 
						|
  if (BootNext != NULL) {
 | 
						|
    FreePool (BootNext);
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // When BootOrder & BootNext conver all numbers in the range [0 ... 0xffff],
 | 
						|
  //   OptionNumber equals to 0x10000 which is not valid.
 | 
						|
  //
 | 
						|
  ASSERT (OptionNumber <= 0x10000);
 | 
						|
  if (OptionNumber == 0x10000) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  } else {
 | 
						|
    *FreeOptionNumber = (UINT16) OptionNumber;
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Create the Boot####, Driver####, SysPrep####, PlatformRecovery#### variable
 | 
						|
  from the load option.
 | 
						|
 | 
						|
  @param  LoadOption      Pointer to the load option.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS     The variable was created.
 | 
						|
  @retval Others          Error status returned by RT->SetVariable.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
EfiBootManagerLoadOptionToVariable (
 | 
						|
  IN CONST EFI_BOOT_MANAGER_LOAD_OPTION     *Option
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                       Status;
 | 
						|
  UINTN                            VariableSize;
 | 
						|
  UINT8                            *Variable;
 | 
						|
  UINT8                            *Ptr;
 | 
						|
  CHAR16                           OptionName[BM_OPTION_NAME_LEN];
 | 
						|
  CHAR16                           *Description;
 | 
						|
  CHAR16                           NullChar;
 | 
						|
  EDKII_VARIABLE_LOCK_PROTOCOL     *VariableLock;
 | 
						|
  UINT32                           VariableAttributes;
 | 
						|
 | 
						|
  if ((Option->OptionNumber == LoadOptionNumberUnassigned) ||
 | 
						|
      (Option->FilePath == NULL) ||
 | 
						|
      ((UINT32) Option->OptionType >= LoadOptionTypeMax)
 | 
						|
     ) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Convert NULL description to empty description
 | 
						|
  //
 | 
						|
  NullChar    = L'\0';
 | 
						|
  Description = Option->Description;
 | 
						|
  if (Description == NULL) {
 | 
						|
    Description = &NullChar;
 | 
						|
  }
 | 
						|
 | 
						|
  /*
 | 
						|
  UINT32                      Attributes;
 | 
						|
  UINT16                      FilePathListLength;
 | 
						|
  CHAR16                      Description[];
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL    FilePathList[];
 | 
						|
  UINT8                       OptionalData[];
 | 
						|
TODO: FilePathList[] IS:
 | 
						|
A packed array of UEFI device paths.  The first element of the 
 | 
						|
array is a device path that describes the device and location of the 
 | 
						|
Image for this load option.  The FilePathList[0] is specific 
 | 
						|
to the device type.  Other device paths may optionally exist in the 
 | 
						|
FilePathList, but their usage is OSV specific. Each element 
 | 
						|
in the array is variable length, and ends at the device path end 
 | 
						|
structure.
 | 
						|
  */
 | 
						|
  VariableSize = sizeof (Option->Attributes)
 | 
						|
               + sizeof (UINT16)
 | 
						|
               + StrSize (Description)
 | 
						|
               + GetDevicePathSize (Option->FilePath)
 | 
						|
               + Option->OptionalDataSize;
 | 
						|
 | 
						|
  Variable     = AllocatePool (VariableSize);
 | 
						|
  ASSERT (Variable != NULL);
 | 
						|
 | 
						|
  Ptr             = Variable;
 | 
						|
  WriteUnaligned32 ((UINT32 *) Ptr, Option->Attributes);
 | 
						|
  Ptr            += sizeof (Option->Attributes);
 | 
						|
 | 
						|
  WriteUnaligned16 ((UINT16 *) Ptr, (UINT16) GetDevicePathSize (Option->FilePath));
 | 
						|
  Ptr            += sizeof (UINT16);
 | 
						|
 | 
						|
  CopyMem (Ptr, Description, StrSize (Description));
 | 
						|
  Ptr            += StrSize (Description);
 | 
						|
 | 
						|
  CopyMem (Ptr, Option->FilePath, GetDevicePathSize (Option->FilePath));
 | 
						|
  Ptr            += GetDevicePathSize (Option->FilePath);
 | 
						|
 | 
						|
  CopyMem (Ptr, Option->OptionalData, Option->OptionalDataSize);
 | 
						|
 | 
						|
  UnicodeSPrint (OptionName, sizeof (OptionName), L"%s%04x", mBmLoadOptionName[Option->OptionType], Option->OptionNumber);
 | 
						|
 | 
						|
  VariableAttributes = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE;
 | 
						|
  if (Option->OptionType == LoadOptionTypePlatformRecovery) {
 | 
						|
    //
 | 
						|
    // Lock the PlatformRecovery####
 | 
						|
    //
 | 
						|
    Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **) &VariableLock);
 | 
						|
    if (!EFI_ERROR (Status)) {
 | 
						|
      Status = VariableLock->RequestToLock (VariableLock, OptionName, &gEfiGlobalVariableGuid);
 | 
						|
      ASSERT_EFI_ERROR (Status);
 | 
						|
    }
 | 
						|
    VariableAttributes = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  return gRT->SetVariable (
 | 
						|
                OptionName,
 | 
						|
                &gEfiGlobalVariableGuid,
 | 
						|
                VariableAttributes,
 | 
						|
                VariableSize,
 | 
						|
                Variable
 | 
						|
                );
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Update order variable .
 | 
						|
 | 
						|
  @param  OptionOrderName     Order variable name which need to be updated.
 | 
						|
  @param  OptionNumber        Option number for the new option.
 | 
						|
  @param  Position            Position of the new load option to put in the ****Order variable.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The boot#### or driver#### have been successfully registered.
 | 
						|
  @retval EFI_ALREADY_STARTED   The option number of Option is being used already.
 | 
						|
  @retval EFI_STATUS            Return the status of gRT->SetVariable ().
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
BmAddOptionNumberToOrderVariable (
 | 
						|
  IN CHAR16               *OptionOrderName,
 | 
						|
  IN UINT16               OptionNumber,
 | 
						|
  IN UINTN                Position
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS              Status;
 | 
						|
  UINTN                   Index;
 | 
						|
  UINT16                  *OptionOrder;
 | 
						|
  UINT16                  *NewOptionOrder;
 | 
						|
  UINTN                   OptionOrderSize;
 | 
						|
  //
 | 
						|
  // Update the option order variable
 | 
						|
  //
 | 
						|
  GetEfiGlobalVariable2 (OptionOrderName, (VOID **) &OptionOrder, &OptionOrderSize);
 | 
						|
  ASSERT ((OptionOrder != NULL && OptionOrderSize != 0) || (OptionOrder == NULL && OptionOrderSize == 0));
 | 
						|
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
  for (Index = 0; Index < OptionOrderSize / sizeof (UINT16); Index++) {
 | 
						|
    if (OptionOrder[Index] == OptionNumber) {
 | 
						|
      Status = EFI_ALREADY_STARTED;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (!EFI_ERROR (Status)) {
 | 
						|
    Position       = MIN (Position, OptionOrderSize / sizeof (UINT16));
 | 
						|
 | 
						|
    NewOptionOrder = AllocatePool (OptionOrderSize + sizeof (UINT16));
 | 
						|
    ASSERT (NewOptionOrder != NULL);
 | 
						|
    if (OptionOrderSize != 0) {
 | 
						|
      CopyMem (NewOptionOrder, OptionOrder, Position * sizeof (UINT16));
 | 
						|
      CopyMem (&NewOptionOrder[Position + 1], &OptionOrder[Position], OptionOrderSize - Position * sizeof (UINT16));
 | 
						|
    }
 | 
						|
    NewOptionOrder[Position] = OptionNumber;
 | 
						|
 | 
						|
    Status = gRT->SetVariable (
 | 
						|
                    OptionOrderName,
 | 
						|
                    &gEfiGlobalVariableGuid,
 | 
						|
                    EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
 | 
						|
                    OptionOrderSize + sizeof (UINT16),
 | 
						|
                    NewOptionOrder
 | 
						|
                    );
 | 
						|
    FreePool (NewOptionOrder);
 | 
						|
  }
 | 
						|
 | 
						|
  if (OptionOrder != NULL) {
 | 
						|
    FreePool (OptionOrder);
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This function will register the new Boot####, Driver#### or SysPrep#### option.
 | 
						|
  After the *#### is updated, the *Order will also be updated.
 | 
						|
 | 
						|
  @param  Option            Pointer to load option to add.
 | 
						|
  @param  Position          Position of the new load option to put in the ****Order variable.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The *#### have been successfully registered.
 | 
						|
  @retval EFI_INVALID_PARAMETER The option number exceeds 0xFFFF.
 | 
						|
  @retval EFI_ALREADY_STARTED   The option number of Option is being used already.
 | 
						|
                                Note: this API only adds new load option, no replacement support.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES  There is no free option number that can be used when the
 | 
						|
                                option number specified in the Option is LoadOptionNumberUnassigned.
 | 
						|
  @retval EFI_STATUS            Return the status of gRT->SetVariable ().
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
EfiBootManagerAddLoadOptionVariable (
 | 
						|
  IN EFI_BOOT_MANAGER_LOAD_OPTION *Option,
 | 
						|
  IN UINTN                        Position
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                      Status;
 | 
						|
  UINT16                          OptionNumber;
 | 
						|
 | 
						|
  if (Option == NULL) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Option->OptionType != LoadOptionTypeDriver && 
 | 
						|
      Option->OptionType != LoadOptionTypeSysPrep &&
 | 
						|
      Option->OptionType != LoadOptionTypeBoot
 | 
						|
      ) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Get the free option number if the option number is unassigned
 | 
						|
  //
 | 
						|
  if (Option->OptionNumber == LoadOptionNumberUnassigned) {
 | 
						|
    Status = BmGetFreeOptionNumber (Option->OptionType, &OptionNumber);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
    Option->OptionNumber = OptionNumber;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Option->OptionNumber >= LoadOptionNumberMax) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = BmAddOptionNumberToOrderVariable (mBmLoadOptionOrderName[Option->OptionType], (UINT16) Option->OptionNumber, Position);
 | 
						|
  if (!EFI_ERROR (Status)) {
 | 
						|
    //
 | 
						|
    // Save the Boot#### or Driver#### variable
 | 
						|
    //
 | 
						|
    Status = EfiBootManagerLoadOptionToVariable (Option);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      //
 | 
						|
      // Remove the #### from *Order variable when the Driver####/SysPrep####/Boot#### cannot be saved.
 | 
						|
      //
 | 
						|
      EfiBootManagerDeleteLoadOptionVariable (Option->OptionNumber, Option->OptionType);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Sort the load option. The DriverOrder or BootOrder will be re-created to 
 | 
						|
  reflect the new order.
 | 
						|
 | 
						|
  @param OptionType             Load option type
 | 
						|
  @param CompareFunction        The comparator
 | 
						|
**/
 | 
						|
VOID
 | 
						|
EFIAPI
 | 
						|
EfiBootManagerSortLoadOptionVariable (
 | 
						|
  EFI_BOOT_MANAGER_LOAD_OPTION_TYPE        OptionType,
 | 
						|
  SORT_COMPARE                             CompareFunction
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                     Status;
 | 
						|
  EFI_BOOT_MANAGER_LOAD_OPTION   *LoadOption;
 | 
						|
  UINTN                          LoadOptionCount;
 | 
						|
  UINTN                          Index;
 | 
						|
  UINT16                         *OptionOrder;
 | 
						|
 | 
						|
  LoadOption = EfiBootManagerGetLoadOptions (&LoadOptionCount, OptionType);
 | 
						|
 | 
						|
  //
 | 
						|
  // Insertion sort algorithm
 | 
						|
  //
 | 
						|
  PerformQuickSort (
 | 
						|
    LoadOption,
 | 
						|
    LoadOptionCount,
 | 
						|
    sizeof (EFI_BOOT_MANAGER_LOAD_OPTION),
 | 
						|
    CompareFunction
 | 
						|
    );
 | 
						|
 | 
						|
  //
 | 
						|
  // Create new ****Order variable
 | 
						|
  //
 | 
						|
  OptionOrder = AllocatePool (LoadOptionCount * sizeof (UINT16));
 | 
						|
  ASSERT (OptionOrder != NULL);
 | 
						|
  for (Index = 0; Index < LoadOptionCount; Index++) {
 | 
						|
    OptionOrder[Index] = (UINT16) LoadOption[Index].OptionNumber;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = gRT->SetVariable (
 | 
						|
                  mBmLoadOptionOrderName[OptionType],
 | 
						|
                  &gEfiGlobalVariableGuid,
 | 
						|
                  EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
 | 
						|
                  LoadOptionCount * sizeof (UINT16),
 | 
						|
                  OptionOrder
 | 
						|
                  );
 | 
						|
  //
 | 
						|
  // Changing the *Order content without increasing its size with current variable implementation shouldn't fail.
 | 
						|
  //
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
 | 
						|
  FreePool (OptionOrder);
 | 
						|
  EfiBootManagerFreeLoadOptions (LoadOption, LoadOptionCount);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Initialize a load option.
 | 
						|
 | 
						|
  @param Option           Pointer to the load option to be initialized.
 | 
						|
  @param OptionNumber     Option number of the load option.
 | 
						|
  @param OptionType       Type of the load option.
 | 
						|
  @param Attributes       Attributes of the load option.
 | 
						|
  @param Description      Description of the load option.
 | 
						|
  @param FilePath         Device path of the load option.
 | 
						|
  @param OptionalData     Optional data of the load option.
 | 
						|
  @param OptionalDataSize Size of the optional data of the load option.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The load option was initialized successfully.
 | 
						|
  @retval EFI_INVALID_PARAMETER Option, Description or FilePath is NULL.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
EfiBootManagerInitializeLoadOption (
 | 
						|
  IN OUT EFI_BOOT_MANAGER_LOAD_OPTION   *Option,
 | 
						|
  IN  UINTN                             OptionNumber,
 | 
						|
  IN  EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType,
 | 
						|
  IN  UINT32                            Attributes,
 | 
						|
  IN  CHAR16                            *Description,
 | 
						|
  IN  EFI_DEVICE_PATH_PROTOCOL          *FilePath,
 | 
						|
  IN  UINT8                             *OptionalData,   OPTIONAL
 | 
						|
  IN  UINT32                            OptionalDataSize
 | 
						|
  )
 | 
						|
{
 | 
						|
  if ((Option == NULL) || (Description == NULL) || (FilePath == NULL)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if (((OptionalData != NULL) && (OptionalDataSize == 0)) ||
 | 
						|
      ((OptionalData == NULL) && (OptionalDataSize != 0))) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((UINT32) OptionType >= LoadOptionTypeMax) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  ZeroMem (Option, sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));
 | 
						|
  Option->OptionNumber       = OptionNumber;
 | 
						|
  Option->OptionType         = OptionType;
 | 
						|
  Option->Attributes         = Attributes;
 | 
						|
  Option->Description        = AllocateCopyPool (StrSize (Description), Description);
 | 
						|
  Option->FilePath           = DuplicateDevicePath (FilePath);
 | 
						|
  if (OptionalData != NULL) {
 | 
						|
    Option->OptionalData     = AllocateCopyPool (OptionalDataSize, OptionalData);
 | 
						|
    Option->OptionalDataSize = OptionalDataSize;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Return the index of the load option in the load option array.
 | 
						|
 | 
						|
  The function consider two load options are equal when the 
 | 
						|
  OptionType, Attributes, Description, FilePath and OptionalData are equal.
 | 
						|
 | 
						|
  @param Key    Pointer to the load option to be found.
 | 
						|
  @param Array  Pointer to the array of load options to be found.
 | 
						|
  @param Count  Number of entries in the Array.
 | 
						|
 | 
						|
  @retval -1          Key wasn't found in the Array.
 | 
						|
  @retval 0 ~ Count-1 The index of the Key in the Array.
 | 
						|
**/
 | 
						|
INTN
 | 
						|
EFIAPI
 | 
						|
EfiBootManagerFindLoadOption (
 | 
						|
  IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Key,
 | 
						|
  IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Array,
 | 
						|
  IN UINTN                              Count
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN                             Index;
 | 
						|
 | 
						|
  for (Index = 0; Index < Count; Index++) {
 | 
						|
    if ((Key->OptionType == Array[Index].OptionType) &&
 | 
						|
        (Key->Attributes == Array[Index].Attributes) &&
 | 
						|
        (StrCmp (Key->Description, Array[Index].Description) == 0) &&
 | 
						|
        (CompareMem (Key->FilePath, Array[Index].FilePath, GetDevicePathSize (Key->FilePath)) == 0) &&
 | 
						|
        (Key->OptionalDataSize == Array[Index].OptionalDataSize) &&
 | 
						|
        (CompareMem (Key->OptionalData, Array[Index].OptionalData, Key->OptionalDataSize) == 0)) {
 | 
						|
      return (INTN) Index;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return -1;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Delete the load option.
 | 
						|
 | 
						|
  @param  OptionNumber        Indicate the option number of load option
 | 
						|
  @param  OptionType          Indicate the type of load option
 | 
						|
 | 
						|
  @retval EFI_INVALID_PARAMETER OptionType or OptionNumber is invalid.
 | 
						|
  @retval EFI_NOT_FOUND         The load option cannot be found
 | 
						|
  @retval EFI_SUCCESS           The load option was deleted
 | 
						|
  @retval others                Status of RT->SetVariable()
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
EfiBootManagerDeleteLoadOptionVariable (
 | 
						|
  IN UINTN                              OptionNumber,
 | 
						|
  IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE  OptionType
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT16                            *OptionOrder;
 | 
						|
  UINTN                             OptionOrderSize;
 | 
						|
  UINTN                             Index;
 | 
						|
  CHAR16                            OptionName[BM_OPTION_NAME_LEN];
 | 
						|
 | 
						|
  if (((UINT32) OptionType >= LoadOptionTypeMax) || (OptionNumber >= LoadOptionNumberMax)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if (OptionType == LoadOptionTypeDriver || OptionType == LoadOptionTypeSysPrep || OptionType == LoadOptionTypeBoot) {
 | 
						|
    //
 | 
						|
    // If the associated *Order exists, firstly remove the reference in *Order for
 | 
						|
    //  Driver####, SysPrep#### and Boot####.
 | 
						|
    //
 | 
						|
    GetEfiGlobalVariable2 (mBmLoadOptionOrderName[OptionType], (VOID **) &OptionOrder, &OptionOrderSize);
 | 
						|
    ASSERT ((OptionOrder != NULL && OptionOrderSize != 0) || (OptionOrder == NULL && OptionOrderSize == 0));
 | 
						|
 | 
						|
    for (Index = 0; Index < OptionOrderSize / sizeof (UINT16); Index++) {
 | 
						|
      if (OptionOrder[Index] == OptionNumber) {
 | 
						|
        OptionOrderSize -= sizeof (UINT16);
 | 
						|
        CopyMem (&OptionOrder[Index], &OptionOrder[Index + 1], OptionOrderSize - Index * sizeof (UINT16));
 | 
						|
        gRT->SetVariable (
 | 
						|
               mBmLoadOptionOrderName[OptionType],
 | 
						|
               &gEfiGlobalVariableGuid,
 | 
						|
               EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
 | 
						|
               OptionOrderSize,
 | 
						|
               OptionOrder
 | 
						|
               );
 | 
						|
        break;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    if (OptionOrder != NULL) {
 | 
						|
      FreePool (OptionOrder);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Remove the Driver####, SysPrep####, Boot#### or PlatformRecovery#### itself.
 | 
						|
  //
 | 
						|
  UnicodeSPrint (OptionName, sizeof (OptionName), L"%s%04x", mBmLoadOptionName[OptionType], OptionNumber);
 | 
						|
  return gRT->SetVariable (
 | 
						|
                OptionName,
 | 
						|
                &gEfiGlobalVariableGuid,
 | 
						|
                0,
 | 
						|
                0,
 | 
						|
                NULL
 | 
						|
                );
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Returns the size of a device path in bytes.
 | 
						|
 | 
						|
  This function returns the size, in bytes, of the device path data structure 
 | 
						|
  specified by DevicePath including the end of device path node. If DevicePath 
 | 
						|
  is NULL, then 0 is returned. If the length of the device path is bigger than
 | 
						|
  MaxSize, also return 0 to indicate this is an invalidate device path.
 | 
						|
 | 
						|
  @param  DevicePath         A pointer to a device path data structure.
 | 
						|
  @param  MaxSize            Max valid device path size. If big than this size, 
 | 
						|
                             return error.
 | 
						|
  
 | 
						|
  @retval 0                  An invalid device path.
 | 
						|
  @retval Others             The size of a device path in bytes.
 | 
						|
 | 
						|
**/
 | 
						|
UINTN
 | 
						|
BmGetDevicePathSizeEx (
 | 
						|
  IN CONST EFI_DEVICE_PATH_PROTOCOL  *DevicePath,
 | 
						|
  IN UINTN                           MaxSize
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN  Size;
 | 
						|
  UINTN  NodeSize;
 | 
						|
 | 
						|
  if (DevicePath == NULL) {
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Search for the end of the device path structure
 | 
						|
  //
 | 
						|
  Size = 0;
 | 
						|
  while (!IsDevicePathEnd (DevicePath)) {
 | 
						|
    NodeSize = DevicePathNodeLength (DevicePath);
 | 
						|
    if (NodeSize == 0) {
 | 
						|
      return 0;
 | 
						|
    }
 | 
						|
    Size += NodeSize;
 | 
						|
    if (Size > MaxSize) {
 | 
						|
      return 0;
 | 
						|
    }
 | 
						|
    DevicePath = NextDevicePathNode (DevicePath);
 | 
						|
  }
 | 
						|
  Size += DevicePathNodeLength (DevicePath);
 | 
						|
  if (Size > MaxSize) {
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  return Size;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Returns the length of a Null-terminated Unicode string. If the length is 
 | 
						|
  bigger than MaxStringLen, return length 0 to indicate that this is an 
 | 
						|
  invalidate string.
 | 
						|
 | 
						|
  This function returns the number of Unicode characters in the Null-terminated
 | 
						|
  Unicode string specified by String. 
 | 
						|
 | 
						|
  If String is NULL, then ASSERT().
 | 
						|
  If String is not aligned on a 16-bit boundary, then ASSERT().
 | 
						|
 | 
						|
  @param  String           A pointer to a Null-terminated Unicode string.
 | 
						|
  @param  MaxStringLen     Max string len in this string.
 | 
						|
 | 
						|
  @retval 0                An invalid string.
 | 
						|
  @retval Others           The length of String.
 | 
						|
 | 
						|
**/
 | 
						|
UINTN
 | 
						|
BmStrSizeEx (
 | 
						|
  IN      CONST CHAR16              *String,
 | 
						|
  IN      UINTN                     MaxStringLen
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN                             Length;
 | 
						|
 | 
						|
  ASSERT (String != NULL && MaxStringLen != 0);
 | 
						|
  ASSERT (((UINTN) String & BIT0) == 0);
 | 
						|
 | 
						|
  for (Length = 0; *String != L'\0' && MaxStringLen != Length; String++, Length+=2);
 | 
						|
 | 
						|
  if (*String != L'\0' && MaxStringLen == Length) {
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  return Length + 2;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Validate the Boot####, Driver####, SysPrep#### and PlatformRecovery####
 | 
						|
  variable (VendorGuid/Name)
 | 
						|
 | 
						|
  @param  Variable              The variable data.
 | 
						|
  @param  VariableSize          The variable size.
 | 
						|
 | 
						|
  @retval TRUE                  The variable data is correct.
 | 
						|
  @retval FALSE                 The variable data is corrupted.
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN 
 | 
						|
BmValidateOption (
 | 
						|
  UINT8                     *Variable,
 | 
						|
  UINTN                     VariableSize
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT16                    FilePathSize;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
 | 
						|
  UINTN                     DescriptionSize;
 | 
						|
 | 
						|
  if (VariableSize <= sizeof (UINT16) + sizeof (UINT32)) {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Skip the option attribute
 | 
						|
  //
 | 
						|
  Variable += sizeof (UINT32);
 | 
						|
 | 
						|
  //
 | 
						|
  // Get the option's device path size
 | 
						|
  //
 | 
						|
  FilePathSize = ReadUnaligned16 ((UINT16 *) Variable);
 | 
						|
  Variable += sizeof (UINT16);
 | 
						|
 | 
						|
  //
 | 
						|
  // Get the option's description string size
 | 
						|
  //
 | 
						|
  DescriptionSize = BmStrSizeEx ((CHAR16 *) Variable, VariableSize - sizeof (UINT16) - sizeof (UINT32));
 | 
						|
  Variable += DescriptionSize;
 | 
						|
 | 
						|
  //
 | 
						|
  // Get the option's device path
 | 
						|
  //
 | 
						|
  DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Variable;
 | 
						|
 | 
						|
  //
 | 
						|
  // Validation boot option variable.
 | 
						|
  //
 | 
						|
  if ((FilePathSize == 0) || (DescriptionSize == 0)) {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  if (sizeof (UINT32) + sizeof (UINT16) + DescriptionSize + FilePathSize > VariableSize) {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  return (BOOLEAN) (BmGetDevicePathSizeEx (DevicePath, FilePathSize) != 0);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Check whether the VariableName is a valid load option variable name
 | 
						|
  and return the load option type and option number.
 | 
						|
 | 
						|
  @param VariableName The name of the load option variable.
 | 
						|
  @param OptionType   Return the load option type.
 | 
						|
  @param OptionNumber Return the load option number.
 | 
						|
 | 
						|
  @retval TRUE  The variable name is valid; The load option type and
 | 
						|
                load option number is returned.
 | 
						|
  @retval FALSE The variable name is NOT valid.
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
EFIAPI
 | 
						|
EfiBootManagerIsValidLoadOptionVariableName (
 | 
						|
  IN CHAR16                             *VariableName,
 | 
						|
  OUT EFI_BOOT_MANAGER_LOAD_OPTION_TYPE *OptionType   OPTIONAL,
 | 
						|
  OUT UINT16                            *OptionNumber OPTIONAL
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN                             VariableNameLen;
 | 
						|
  UINTN                             Index;
 | 
						|
  UINTN                             Uint;
 | 
						|
 | 
						|
  if (VariableName == NULL) {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  VariableNameLen = StrLen (VariableName);
 | 
						|
 | 
						|
  if (VariableNameLen <= 4) {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  for (Index = 0; Index < ARRAY_SIZE (mBmLoadOptionName); Index++) {
 | 
						|
    if ((VariableNameLen - 4 == StrLen (mBmLoadOptionName[Index])) &&
 | 
						|
        (StrnCmp (VariableName, mBmLoadOptionName[Index], VariableNameLen - 4) == 0)
 | 
						|
        ) {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (Index == ARRAY_SIZE (mBmLoadOptionName)) {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  if (OptionType != NULL) {
 | 
						|
    *OptionType = (EFI_BOOT_MANAGER_LOAD_OPTION_TYPE) Index;
 | 
						|
  }
 | 
						|
 | 
						|
  if (OptionNumber != NULL) {
 | 
						|
    *OptionNumber = 0;
 | 
						|
    for (Index = VariableNameLen - 4; Index < VariableNameLen; Index++) {
 | 
						|
      Uint = BmCharToUint (VariableName[Index]);
 | 
						|
      if (Uint == -1) {
 | 
						|
        break;
 | 
						|
      } else {
 | 
						|
        *OptionNumber = (UINT16) Uint + *OptionNumber * 0x10;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return (BOOLEAN) (Index == VariableNameLen);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Build the Boot#### or Driver#### option from the VariableName.
 | 
						|
 | 
						|
  @param  VariableName          Variable name of the load option
 | 
						|
  @param  VendorGuid            Variable GUID of the load option
 | 
						|
  @param  Option                Return the load option.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS     Get the option just been created
 | 
						|
  @retval EFI_NOT_FOUND   Failed to get the new option
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
EfiBootManagerVariableToLoadOptionEx (
 | 
						|
  IN CHAR16                           *VariableName,
 | 
						|
  IN EFI_GUID                         *VendorGuid,
 | 
						|
  IN OUT EFI_BOOT_MANAGER_LOAD_OPTION *Option  
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                         Status;
 | 
						|
  UINT32                             Attribute;
 | 
						|
  UINT16                             FilePathSize;
 | 
						|
  UINT8                              *Variable;
 | 
						|
  UINT8                              *VariablePtr;
 | 
						|
  UINTN                              VariableSize;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL           *FilePath;
 | 
						|
  UINT8                              *OptionalData;
 | 
						|
  UINT32                             OptionalDataSize;
 | 
						|
  CHAR16                             *Description;
 | 
						|
  EFI_BOOT_MANAGER_LOAD_OPTION_TYPE  OptionType;
 | 
						|
  UINT16                             OptionNumber;
 | 
						|
 | 
						|
  if ((VariableName == NULL) || (Option == NULL)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if (!EfiBootManagerIsValidLoadOptionVariableName (VariableName, &OptionType, &OptionNumber)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Read the variable
 | 
						|
  //
 | 
						|
  GetVariable2 (VariableName, VendorGuid, (VOID **) &Variable, &VariableSize);
 | 
						|
  if (Variable == NULL) {
 | 
						|
    return EFI_NOT_FOUND;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Validate *#### variable data.
 | 
						|
  //
 | 
						|
  if (!BmValidateOption(Variable, VariableSize)) {
 | 
						|
    FreePool (Variable);
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Get the option attribute
 | 
						|
  //
 | 
						|
  VariablePtr = Variable;
 | 
						|
  Attribute = ReadUnaligned32 ((UINT32 *) VariablePtr);
 | 
						|
  VariablePtr += sizeof (UINT32);
 | 
						|
 | 
						|
  //
 | 
						|
  // Get the option's device path size
 | 
						|
  //
 | 
						|
  FilePathSize = ReadUnaligned16 ((UINT16 *) VariablePtr);
 | 
						|
  VariablePtr += sizeof (UINT16);
 | 
						|
 | 
						|
  //
 | 
						|
  // Get the option's description string
 | 
						|
  //
 | 
						|
  Description = (CHAR16 *) VariablePtr;
 | 
						|
 | 
						|
  //
 | 
						|
  // Get the option's description string size
 | 
						|
  //
 | 
						|
  VariablePtr += StrSize ((CHAR16 *) VariablePtr);
 | 
						|
 | 
						|
  //
 | 
						|
  // Get the option's device path
 | 
						|
  //
 | 
						|
  FilePath = (EFI_DEVICE_PATH_PROTOCOL *) VariablePtr;
 | 
						|
  VariablePtr += FilePathSize;
 | 
						|
 | 
						|
  OptionalDataSize = (UINT32) (VariableSize - (UINTN) (VariablePtr - Variable));
 | 
						|
  if (OptionalDataSize == 0) {
 | 
						|
    OptionalData = NULL;
 | 
						|
  } else {
 | 
						|
    OptionalData = VariablePtr;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = EfiBootManagerInitializeLoadOption (
 | 
						|
             Option,
 | 
						|
             OptionNumber,
 | 
						|
             OptionType,
 | 
						|
             Attribute,
 | 
						|
             Description,
 | 
						|
             FilePath,
 | 
						|
             OptionalData,
 | 
						|
             OptionalDataSize
 | 
						|
             );
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
 | 
						|
  CopyGuid (&Option->VendorGuid, VendorGuid);
 | 
						|
 | 
						|
  FreePool (Variable);
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
Build the Boot#### or Driver#### option from the VariableName.
 | 
						|
 | 
						|
@param  VariableName          EFI Variable name indicate if it is Boot#### or Driver####
 | 
						|
@param  Option                Return the Boot#### or Driver#### option.
 | 
						|
 | 
						|
@retval EFI_SUCCESS     Get the option just been created
 | 
						|
@retval EFI_NOT_FOUND   Failed to get the new option
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
EfiBootManagerVariableToLoadOption (
 | 
						|
  IN  CHAR16                          *VariableName,
 | 
						|
  IN OUT EFI_BOOT_MANAGER_LOAD_OPTION *Option
 | 
						|
  )
 | 
						|
{
 | 
						|
  return EfiBootManagerVariableToLoadOptionEx (VariableName, &gEfiGlobalVariableGuid, Option);
 | 
						|
}
 | 
						|
 | 
						|
typedef struct {
 | 
						|
  EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType;
 | 
						|
  EFI_GUID                          *Guid;
 | 
						|
  EFI_BOOT_MANAGER_LOAD_OPTION      *Options;
 | 
						|
  UINTN                             OptionCount;
 | 
						|
} BM_COLLECT_LOAD_OPTIONS_PARAM;
 | 
						|
 | 
						|
/**
 | 
						|
  Visitor function to collect the Platform Recovery load options or OS Recovery
 | 
						|
  load options from NV storage.
 | 
						|
 | 
						|
  @param Name    Variable name.
 | 
						|
  @param Guid    Variable GUID.
 | 
						|
  @param Context The same context passed to BmForEachVariable.
 | 
						|
**/
 | 
						|
VOID
 | 
						|
BmCollectLoadOptions (
 | 
						|
  IN CHAR16               *Name,
 | 
						|
  IN EFI_GUID             *Guid,
 | 
						|
  IN VOID                 *Context
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                        Status;
 | 
						|
  EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType;
 | 
						|
  UINT16                            OptionNumber;
 | 
						|
  EFI_BOOT_MANAGER_LOAD_OPTION      Option;
 | 
						|
  UINTN                             Index;
 | 
						|
  BM_COLLECT_LOAD_OPTIONS_PARAM     *Param;
 | 
						|
 | 
						|
  Param = (BM_COLLECT_LOAD_OPTIONS_PARAM *) Context;
 | 
						|
 | 
						|
  if (CompareGuid (Guid, Param->Guid) && (
 | 
						|
      Param->OptionType == LoadOptionTypePlatformRecovery &&
 | 
						|
      EfiBootManagerIsValidLoadOptionVariableName (Name, &OptionType, &OptionNumber) &&
 | 
						|
      OptionType == LoadOptionTypePlatformRecovery
 | 
						|
     )) {
 | 
						|
    Status = EfiBootManagerVariableToLoadOptionEx (Name, Guid, &Option);
 | 
						|
    if (!EFI_ERROR (Status)) {
 | 
						|
      for (Index = 0; Index < Param->OptionCount; Index++) {
 | 
						|
        if (Param->Options[Index].OptionNumber > Option.OptionNumber) {
 | 
						|
          break;
 | 
						|
        }
 | 
						|
      }
 | 
						|
      Param->Options = ReallocatePool (
 | 
						|
                         Param->OptionCount * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION),
 | 
						|
                         (Param->OptionCount + 1) * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION),
 | 
						|
                         Param->Options
 | 
						|
                         );
 | 
						|
      ASSERT (Param->Options != NULL);
 | 
						|
      CopyMem (&Param->Options[Index + 1], &Param->Options[Index], (Param->OptionCount - Index) * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));
 | 
						|
      CopyMem (&Param->Options[Index], &Option, sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));
 | 
						|
      Param->OptionCount++;
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Returns an array of load options based on the EFI variable
 | 
						|
  L"BootOrder"/L"DriverOrder" and the L"Boot####"/L"Driver####" variables impled by it.
 | 
						|
  #### is the hex value of the UINT16 in each BootOrder/DriverOrder entry. 
 | 
						|
 | 
						|
  @param  LoadOptionCount   Returns number of entries in the array.
 | 
						|
  @param  LoadOptionType    The type of the load option.
 | 
						|
 | 
						|
  @retval NULL  No load options exist.
 | 
						|
  @retval !NULL Array of load option entries.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_BOOT_MANAGER_LOAD_OPTION *
 | 
						|
EFIAPI
 | 
						|
EfiBootManagerGetLoadOptions (
 | 
						|
  OUT UINTN                             *OptionCount,
 | 
						|
  IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE  LoadOptionType
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                    Status;
 | 
						|
  UINT16                        *OptionOrder;
 | 
						|
  UINTN                         OptionOrderSize;
 | 
						|
  UINTN                         Index;
 | 
						|
  UINTN                         OptionIndex;
 | 
						|
  EFI_BOOT_MANAGER_LOAD_OPTION  *Options;
 | 
						|
  CHAR16                        OptionName[BM_OPTION_NAME_LEN];
 | 
						|
  UINT16                        OptionNumber;
 | 
						|
  BM_COLLECT_LOAD_OPTIONS_PARAM Param;
 | 
						|
 | 
						|
  *OptionCount = 0;
 | 
						|
  Options      = NULL;
 | 
						|
 | 
						|
  if (LoadOptionType == LoadOptionTypeDriver || LoadOptionType == LoadOptionTypeSysPrep || LoadOptionType == LoadOptionTypeBoot) {
 | 
						|
    //
 | 
						|
    // Read the BootOrder, or DriverOrder variable.
 | 
						|
    //
 | 
						|
    GetEfiGlobalVariable2 (mBmLoadOptionOrderName[LoadOptionType], (VOID **) &OptionOrder, &OptionOrderSize);
 | 
						|
    if (OptionOrder == NULL) {
 | 
						|
      return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    *OptionCount = OptionOrderSize / sizeof (UINT16);
 | 
						|
 | 
						|
    Options = AllocatePool (*OptionCount * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));
 | 
						|
    ASSERT (Options != NULL);
 | 
						|
 | 
						|
    OptionIndex = 0;
 | 
						|
    for (Index = 0; Index < *OptionCount; Index++) {
 | 
						|
      OptionNumber = OptionOrder[Index];
 | 
						|
      UnicodeSPrint (OptionName, sizeof (OptionName), L"%s%04x", mBmLoadOptionName[LoadOptionType], OptionNumber);
 | 
						|
 | 
						|
      Status = EfiBootManagerVariableToLoadOption (OptionName, &Options[OptionIndex]);
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        DEBUG ((EFI_D_INFO, "[Bds] %s doesn't exist - Update ****Order variable to remove the reference!!", OptionName));
 | 
						|
        EfiBootManagerDeleteLoadOptionVariable (OptionNumber, LoadOptionType);
 | 
						|
      } else {
 | 
						|
        ASSERT (Options[OptionIndex].OptionNumber == OptionNumber);
 | 
						|
        OptionIndex++;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    if (OptionOrder != NULL) {
 | 
						|
      FreePool (OptionOrder);
 | 
						|
    }
 | 
						|
 | 
						|
    if (OptionIndex < *OptionCount) {
 | 
						|
      Options = ReallocatePool (*OptionCount * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION), OptionIndex * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION), Options);
 | 
						|
      ASSERT (Options != NULL);
 | 
						|
      *OptionCount = OptionIndex;
 | 
						|
    }
 | 
						|
 | 
						|
  } else if (LoadOptionType == LoadOptionTypePlatformRecovery) {
 | 
						|
    Param.OptionType = LoadOptionTypePlatformRecovery;
 | 
						|
    Param.Options = NULL;
 | 
						|
    Param.OptionCount = 0;
 | 
						|
    Param.Guid = &gEfiGlobalVariableGuid;
 | 
						|
 | 
						|
    BmForEachVariable (BmCollectLoadOptions, (VOID *) &Param);
 | 
						|
 | 
						|
    *OptionCount = Param.OptionCount;
 | 
						|
    Options = Param.Options;
 | 
						|
  }
 | 
						|
 | 
						|
  return Options;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Free an EFI_BOOT_MANGER_LOAD_OPTION entry that was allocate by the library.
 | 
						|
 | 
						|
  @param  LoadOption   Pointer to boot option to Free.
 | 
						|
 | 
						|
  @return EFI_SUCCESS   BootOption was freed 
 | 
						|
  @return EFI_NOT_FOUND BootOption == NULL 
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
EfiBootManagerFreeLoadOption (
 | 
						|
  IN  EFI_BOOT_MANAGER_LOAD_OPTION  *LoadOption
 | 
						|
  )
 | 
						|
{
 | 
						|
  if (LoadOption == NULL) {
 | 
						|
    return EFI_NOT_FOUND;
 | 
						|
  }
 | 
						|
 | 
						|
  if (LoadOption->Description != NULL) {
 | 
						|
    FreePool (LoadOption->Description);
 | 
						|
  }
 | 
						|
  if (LoadOption->FilePath != NULL) {
 | 
						|
    FreePool (LoadOption->FilePath);
 | 
						|
  }
 | 
						|
  if (LoadOption->OptionalData != NULL) {
 | 
						|
    FreePool (LoadOption->OptionalData);
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Free an EFI_BOOT_MANGER_LOAD_OPTION array that was allocated by 
 | 
						|
  EfiBootManagerGetLoadOptions().
 | 
						|
 | 
						|
  @param  Option       Pointer to boot option array to free.
 | 
						|
  @param  OptionCount  Number of array entries in BootOption
 | 
						|
 | 
						|
  @return EFI_SUCCESS   BootOption was freed 
 | 
						|
  @return EFI_NOT_FOUND BootOption == NULL 
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
EfiBootManagerFreeLoadOptions (
 | 
						|
  IN  EFI_BOOT_MANAGER_LOAD_OPTION  *Option,
 | 
						|
  IN  UINTN                         OptionCount
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN   Index;
 | 
						|
 | 
						|
  if (Option == NULL) {
 | 
						|
    return EFI_NOT_FOUND;
 | 
						|
  }
 | 
						|
 | 
						|
  for (Index = 0;Index < OptionCount; Index++) {
 | 
						|
    EfiBootManagerFreeLoadOption (&Option[Index]);
 | 
						|
  }
 | 
						|
 | 
						|
  FreePool (Option);
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Return whether the PE header of the load option is valid or not.
 | 
						|
 | 
						|
  @param[in] Type       The load option type.
 | 
						|
  @param[in] FileBuffer The PE file buffer of the load option.
 | 
						|
  @param[in] FileSize   The size of the load option file.
 | 
						|
 | 
						|
  @retval TRUE  The PE header of the load option is valid.
 | 
						|
  @retval FALSE The PE header of the load option is not valid.
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
BmIsLoadOptionPeHeaderValid (
 | 
						|
  IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE Type,
 | 
						|
  IN VOID                              *FileBuffer,
 | 
						|
  IN UINTN                             FileSize
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_IMAGE_DOS_HEADER              *DosHeader;
 | 
						|
  EFI_IMAGE_OPTIONAL_HEADER_UNION   *PeHeader;
 | 
						|
  EFI_IMAGE_OPTIONAL_HEADER32       *OptionalHeader;
 | 
						|
  UINT16                            Subsystem;
 | 
						|
 | 
						|
  if (FileBuffer == NULL || FileSize == 0) {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Read dos header
 | 
						|
  //
 | 
						|
  DosHeader = (EFI_IMAGE_DOS_HEADER *) FileBuffer;
 | 
						|
  if (FileSize >= sizeof (EFI_IMAGE_DOS_HEADER) &&
 | 
						|
      FileSize > DosHeader->e_lfanew && DosHeader->e_magic == EFI_IMAGE_DOS_SIGNATURE
 | 
						|
      ) {
 | 
						|
    //
 | 
						|
    // Read and check PE signature
 | 
						|
    //
 | 
						|
    PeHeader = (EFI_IMAGE_OPTIONAL_HEADER_UNION *) ((UINT8 *) FileBuffer + DosHeader->e_lfanew);
 | 
						|
    if (FileSize >= DosHeader->e_lfanew + sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION) &&
 | 
						|
        PeHeader->Pe32.Signature == EFI_IMAGE_NT_SIGNATURE
 | 
						|
        ) {
 | 
						|
      //
 | 
						|
      // Check PE32 or PE32+ magic, and machine type
 | 
						|
      //
 | 
						|
      OptionalHeader = (EFI_IMAGE_OPTIONAL_HEADER32 *) &PeHeader->Pe32.OptionalHeader;
 | 
						|
      if ((OptionalHeader->Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC || 
 | 
						|
           OptionalHeader->Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) &&
 | 
						|
          EFI_IMAGE_MACHINE_TYPE_SUPPORTED (PeHeader->Pe32.FileHeader.Machine)
 | 
						|
          ) {
 | 
						|
        //
 | 
						|
        // Check the Subsystem:
 | 
						|
        //   Driver#### must be of type BootServiceDriver or RuntimeDriver
 | 
						|
        //   SysPrep####, Boot####, OsRecovery####, PlatformRecovery#### must be of type Application
 | 
						|
        //
 | 
						|
        Subsystem = OptionalHeader->Subsystem;
 | 
						|
        if ((Type == LoadOptionTypeDriver && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) ||
 | 
						|
            (Type == LoadOptionTypeDriver && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) ||
 | 
						|
            (Type == LoadOptionTypeSysPrep && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) ||
 | 
						|
            (Type == LoadOptionTypeBoot && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) ||
 | 
						|
            (Type == LoadOptionTypePlatformRecovery && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION)
 | 
						|
            ) {
 | 
						|
          return TRUE;
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Process (load and execute) the load option.
 | 
						|
 | 
						|
  @param LoadOption  Pointer to the load option.
 | 
						|
 | 
						|
  @retval EFI_INVALID_PARAMETER  The load option type is invalid, 
 | 
						|
                                 or the load option file path doesn't point to a valid file.
 | 
						|
  @retval EFI_UNSUPPORTED        The load option type is of LoadOptionTypeBoot.
 | 
						|
  @retval EFI_SUCCESS            The load option is inactive, or successfully loaded and executed.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
EfiBootManagerProcessLoadOption (
 | 
						|
  IN EFI_BOOT_MANAGER_LOAD_OPTION       *LoadOption
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                        Status;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL          *FilePath;
 | 
						|
  EFI_HANDLE                        ImageHandle;
 | 
						|
  EFI_LOADED_IMAGE_PROTOCOL         *ImageInfo;
 | 
						|
  VOID                              *FileBuffer;
 | 
						|
  UINTN                             FileSize;
 | 
						|
 | 
						|
  if ((UINT32) LoadOption->OptionType >= LoadOptionTypeMax) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if (LoadOption->OptionType == LoadOptionTypeBoot) {
 | 
						|
    return EFI_UNSUPPORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // If a load option is not marked as LOAD_OPTION_ACTIVE,
 | 
						|
  // the boot manager will not automatically load the option.
 | 
						|
  //
 | 
						|
  if ((LoadOption->Attributes & LOAD_OPTION_ACTIVE) == 0) {
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = EFI_INVALID_PARAMETER;
 | 
						|
 | 
						|
  //
 | 
						|
  // Load and start the load option.
 | 
						|
  //
 | 
						|
  DEBUG ((
 | 
						|
    DEBUG_INFO | DEBUG_LOAD, "Process %s%04x (%s) ...\n",
 | 
						|
    mBmLoadOptionName[LoadOption->OptionType], LoadOption->OptionNumber,
 | 
						|
    LoadOption->Description
 | 
						|
    ));
 | 
						|
  ImageHandle = NULL;
 | 
						|
  FileBuffer = EfiBootManagerGetLoadOptionBuffer (LoadOption->FilePath, &FilePath, &FileSize);
 | 
						|
  DEBUG_CODE (
 | 
						|
    if (FileBuffer != NULL && CompareMem (LoadOption->FilePath, FilePath, GetDevicePathSize (FilePath)) != 0) {
 | 
						|
      DEBUG ((EFI_D_INFO, "[Bds] DevicePath expand: "));
 | 
						|
      BmPrintDp (LoadOption->FilePath);
 | 
						|
      DEBUG ((EFI_D_INFO, " -> "));
 | 
						|
      BmPrintDp (FilePath);
 | 
						|
      DEBUG ((EFI_D_INFO, "\n"));
 | 
						|
    }
 | 
						|
  );
 | 
						|
  if (BmIsLoadOptionPeHeaderValid (LoadOption->OptionType, FileBuffer, FileSize)) {
 | 
						|
    Status = gBS->LoadImage (
 | 
						|
                    FALSE,
 | 
						|
                    gImageHandle,
 | 
						|
                    FilePath,
 | 
						|
                    FileBuffer,
 | 
						|
                    FileSize,
 | 
						|
                    &ImageHandle
 | 
						|
                    );
 | 
						|
  }
 | 
						|
  if (FilePath != NULL) {
 | 
						|
    FreePool (FilePath);
 | 
						|
  }
 | 
						|
  if (FileBuffer != NULL) {
 | 
						|
    FreePool (FileBuffer);
 | 
						|
  }
 | 
						|
 | 
						|
  if (!EFI_ERROR (Status)) {
 | 
						|
    Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo);
 | 
						|
    ASSERT_EFI_ERROR (Status);
 | 
						|
 | 
						|
    ImageInfo->LoadOptionsSize = LoadOption->OptionalDataSize;
 | 
						|
    ImageInfo->LoadOptions = LoadOption->OptionalData;
 | 
						|
    //
 | 
						|
    // Before calling the image, enable the Watchdog Timer for the 5-minute period
 | 
						|
    //
 | 
						|
    gBS->SetWatchdogTimer (5 * 60, 0, 0, NULL);
 | 
						|
 | 
						|
    LoadOption->Status = gBS->StartImage (ImageHandle, &LoadOption->ExitDataSize, &LoadOption->ExitData);
 | 
						|
    DEBUG ((
 | 
						|
      DEBUG_INFO | DEBUG_LOAD, "%s%04x Return Status = %r\n",
 | 
						|
      mBmLoadOptionName[LoadOption->OptionType], LoadOption->OptionNumber, LoadOption->Status
 | 
						|
      ));
 | 
						|
 | 
						|
    //
 | 
						|
    // Clear the Watchdog Timer after the image returns
 | 
						|
    //
 | 
						|
    gBS->SetWatchdogTimer (0, 0, 0, NULL);
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 |