UefiBootManagerLib provides: load option library functions; hot key library functions; boot library functions; connect and disconnect library functions; driver health library functions. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ruiyu Ni <ruiyu.ni@intel.com> Reviewed-by: Eric Dong <eric.dong@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@17327 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			983 lines
		
	
	
		
			29 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			983 lines
		
	
	
		
			29 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   Load option library functions which relate with creating and processing load options.
 | |
| 
 | |
| Copyright (c) 2011 - 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 "InternalBm.h"
 | |
| 
 | |
| /**
 | |
|   Get the Option Number that wasn't used.
 | |
| 
 | |
|   @param  OrderVariableName   Could be L"BootOrder" or L"DriverOrder".
 | |
|   @param  FreeOptionNumber    To receive the minimal free option number.
 | |
| 
 | |
|   @retval EFI_SUCCESS           The option number is found
 | |
|   @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  CHAR16    *OrderVariableName,
 | |
|   OUT UINT16    *FreeOptionNumber
 | |
|   )
 | |
| {
 | |
|   
 | |
|   UINTN         OptionNumber;
 | |
|   UINTN         Index;
 | |
|   UINT16        *OptionOrder;
 | |
|   UINTN         OptionOrderSize;
 | |
|   UINT16        *BootNext;
 | |
| 
 | |
|   if (FreeOptionNumber == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   GetEfiGlobalVariable2 (OrderVariableName, (VOID **) &OptionOrder, &OptionOrderSize);
 | |
|   BootNext = NULL;
 | |
|   if (*OrderVariableName == L'B') {
 | |
|     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;
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   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);
 | |
| 
 | |
|   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;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Create the Boot#### or Driver#### 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
 | |
|   )
 | |
| {
 | |
|   UINTN                            VariableSize;
 | |
|   UINT8                            *Variable;
 | |
|   UINT8                            *Ptr;
 | |
|   CHAR16                           OptionName[sizeof ("Driver####")];
 | |
|   CHAR16                           *Description;
 | |
|   CHAR16                           NullChar;
 | |
| 
 | |
|   if ((Option->OptionNumber == LoadOptionNumberUnassigned) ||
 | |
|       (Option->FilePath == NULL) ||
 | |
|       (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;
 | |
|   *(UINT32 *) Ptr = Option->Attributes;
 | |
|   Ptr            += sizeof (Option->Attributes);
 | |
|   *(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),
 | |
|     (Option->OptionType == LoadOptionTypeBoot) ? L"Boot%04x" : L"Driver%04x",
 | |
|     Option->OptionNumber
 | |
|     );
 | |
| 
 | |
|   return gRT->SetVariable (
 | |
|                 OptionName,
 | |
|                 &gEfiGlobalVariableGuid,
 | |
|                 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
 | |
|                 VariableSize,
 | |
|                 Variable
 | |
|                 );
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This function will register the new boot#### or driver#### option.
 | |
|   After the boot#### or driver#### updated, the BootOrder or DriverOrder 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 boot#### or driver#### 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;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Get the free option number if the option number is unassigned
 | |
|   //
 | |
|   if (Option->OptionNumber == LoadOptionNumberUnassigned) {
 | |
|     Status = BmGetFreeOptionNumber (
 | |
|                Option->OptionType == LoadOptionTypeBoot ? L"BootOrder" : L"DriverOrder",
 | |
|                &OptionNumber
 | |
|                );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return Status;
 | |
|     }
 | |
|     Option->OptionNumber = OptionNumber;
 | |
|   }
 | |
| 
 | |
|   if (Option->OptionNumber >= LoadOptionNumberMax) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   Status = BmAddOptionNumberToOrderVariable (
 | |
|              Option->OptionType == LoadOptionTypeBoot ? L"BootOrder" : L"DriverOrder",
 | |
|              (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 Boot####/Driver#### 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 (
 | |
|                   OptionType == LoadOptionTypeBoot ? L"BootOrder" : L"DriverOrder",
 | |
|                   &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;
 | |
|   }
 | |
| 
 | |
|   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
 | |
| BmFindLoadOption (
 | |
|   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;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Update the BootOrder or DriverOrder to delete OptionNumber .
 | |
| 
 | |
|   @param  OptionOrderVariable  Order variable name which need to be updated.
 | |
|   @param  OptionNumber         Indicate the option number of load option
 | |
| 
 | |
|   @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
 | |
| BmDeleteOptionVariable (
 | |
|   IN CHAR16                            *OptionOrderVariable,
 | |
|   IN UINT16                            OptionNumber
 | |
|   )
 | |
| {
 | |
|   UINT16           *OptionOrder;
 | |
|   UINTN            OptionOrderSize;
 | |
|   EFI_STATUS       Status;
 | |
|   UINTN            Index;
 | |
| 
 | |
|   Status      = EFI_NOT_FOUND;
 | |
|   GetEfiGlobalVariable2 (OptionOrderVariable, (VOID **) &OptionOrder, &OptionOrderSize);
 | |
|   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));
 | |
|       Status = gRT->SetVariable (
 | |
|                       OptionOrderVariable,
 | |
|                       &gEfiGlobalVariableGuid,
 | |
|                       EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
 | |
|                       OptionOrderSize,
 | |
|                       OptionOrder
 | |
|                       );
 | |
|       break;
 | |
|     }
 | |
|   }
 | |
|   if (OptionOrder != NULL) {
 | |
|     FreePool (OptionOrder);
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Update the BootOrder or DriverOrder according to the OptionType to delete OptionNumber .
 | |
|   
 | |
|   @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
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| EfiBootManagerDeleteLoadOptionVariable (
 | |
|   IN UINTN                              OptionNumber,
 | |
|   IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE  OptionType
 | |
|   )
 | |
| {
 | |
|   if ((OptionType >= LoadOptionTypeMax) || (OptionNumber >= LoadOptionNumberMax)) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   return BmDeleteOptionVariable (
 | |
|            OptionType == LoadOptionTypeBoot ? L"BootOrder" : L"DriverOrder",
 | |
|            (UINT16) OptionNumber
 | |
|            );
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Convert a single character to number.
 | |
|   It assumes the input Char is in the scope of L'0' ~ L'9' and L'A' ~ L'F'
 | |
| 
 | |
|   @param    Char   The input char which need to convert to int.
 | |
| **/
 | |
| UINTN
 | |
| BmCharToUint (
 | |
|   IN CHAR16                           Char
 | |
|   )
 | |
| {
 | |
|   if ((Char >= L'0') && (Char <= L'9')) {
 | |
|     return (UINTN) (Char - L'0');
 | |
|   }
 | |
| 
 | |
|   if ((Char >= L'A') && (Char <= L'F')) {
 | |
|     return (UINTN) (Char - L'A' + 0xA);
 | |
|   }
 | |
| 
 | |
|   ASSERT (FALSE);
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   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 EFI Boot#### variable (VendorGuid/Name)
 | |
| 
 | |
|   @param  Variable              Boot#### variable data.
 | |
|   @param  VariableSize          Returns the size of the EFI variable that was read
 | |
| 
 | |
|   @retval TRUE                  The variable data is correct.
 | |
|   @retval FALSE                 The variable data is corrupted.
 | |
| 
 | |
| **/
 | |
| BOOLEAN 
 | |
| BmValidateOption (
 | |
|   UINT8                     *Variable,
 | |
|   UINTN                     VariableSize
 | |
|   )
 | |
| {
 | |
|   UINT16                    FilePathSize;
 | |
|   UINT8                     *TempPtr;
 | |
|   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
 | |
|   UINTN                     TempSize;
 | |
| 
 | |
|   if (VariableSize <= sizeof (UINT16) + sizeof (UINT32)) {
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Skip the option attribute
 | |
|   //
 | |
|   TempPtr    = Variable;
 | |
|   TempPtr   += sizeof (UINT32);
 | |
| 
 | |
|   //
 | |
|   // Get the option's device path size
 | |
|   //
 | |
|   FilePathSize  = *(UINT16 *) TempPtr;
 | |
|   TempPtr      += sizeof (UINT16);
 | |
| 
 | |
|   //
 | |
|   // Get the option's description string size
 | |
|   //
 | |
|   TempSize = BmStrSizeEx ((CHAR16 *) TempPtr, VariableSize - sizeof (UINT16) - sizeof (UINT32));
 | |
|   TempPtr += TempSize;
 | |
| 
 | |
|   //
 | |
|   // Get the option's device path
 | |
|   //
 | |
|   DevicePath =  (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;
 | |
|   TempPtr   += FilePathSize;
 | |
| 
 | |
|   //
 | |
|   // Validation boot option variable.
 | |
|   //
 | |
|   if ((FilePathSize == 0) || (TempSize == 0)) {
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   if (TempSize + FilePathSize + sizeof (UINT16) + sizeof (UINT32) > VariableSize) {
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   return (BOOLEAN) (BmGetDevicePathSizeEx (DevicePath, FilePathSize) != 0);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   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
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                         Status;
 | |
|   UINT32                             Attribute;
 | |
|   UINT16                             FilePathSize;
 | |
|   UINT8                              *Variable;
 | |
|   UINT8                              *TempPtr;
 | |
|   UINTN                              VariableSize;
 | |
|   EFI_DEVICE_PATH_PROTOCOL           *FilePath;
 | |
|   UINT8                              *OptionalData;
 | |
|   UINT32                             OptionalDataSize;
 | |
|   CHAR16                             *Description;
 | |
|   UINT8                              NumOff;
 | |
|   EFI_BOOT_MANAGER_LOAD_OPTION_TYPE  OptionType;
 | |
|   UINT16                             OptionNumber;
 | |
| 
 | |
|   if ((VariableName == NULL) || (Option == NULL)) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Read the variable
 | |
|   //
 | |
|   GetEfiGlobalVariable2 (VariableName, (VOID **) &Variable, &VariableSize);
 | |
|   if (Variable == NULL) {
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Validate Boot#### variable data.
 | |
|   //
 | |
|   if (!BmValidateOption(Variable, VariableSize)) {
 | |
|     FreePool (Variable);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Notes: careful defined the variable of Boot#### or
 | |
|   // Driver####, consider use some macro to abstract the code
 | |
|   //
 | |
|   //
 | |
|   // Get the option attribute
 | |
|   //
 | |
|   TempPtr   =  Variable;
 | |
|   Attribute =  *(UINT32 *) Variable;
 | |
|   TempPtr   += sizeof (UINT32);
 | |
| 
 | |
|   //
 | |
|   // Get the option's device path size
 | |
|   //
 | |
|   FilePathSize =  *(UINT16 *) TempPtr;
 | |
|   TempPtr     += sizeof (UINT16);
 | |
| 
 | |
|   //
 | |
|   // Get the option's description string
 | |
|   //
 | |
|   Description  = (CHAR16 *) TempPtr;
 | |
| 
 | |
|   //
 | |
|   // Get the option's description string size
 | |
|   //
 | |
|   TempPtr     += StrSize ((CHAR16 *) TempPtr);
 | |
| 
 | |
|   //
 | |
|   // Get the option's device path
 | |
|   //
 | |
|   FilePath     =  (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;
 | |
|   TempPtr     += FilePathSize;
 | |
| 
 | |
|   OptionalDataSize = (UINT32) (VariableSize - (UINTN) (TempPtr - Variable));
 | |
|   if (OptionalDataSize == 0) {
 | |
|     OptionalData = NULL;
 | |
|   } else {
 | |
|     OptionalData = TempPtr;
 | |
|   }
 | |
| 
 | |
|   if (*VariableName == L'B') {
 | |
|     OptionType = LoadOptionTypeBoot;
 | |
|     NumOff = (UINT8) (sizeof (L"Boot") / sizeof (CHAR16) - 1);
 | |
|   } else {
 | |
|     OptionType = LoadOptionTypeDriver;
 | |
|     NumOff = (UINT8) (sizeof (L"Driver") / sizeof (CHAR16) - 1);
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // Get the value from VariableName Unicode string
 | |
|   // since the ISO standard assumes ASCII equivalent abbreviations, we can be safe in converting this
 | |
|   // Unicode stream to ASCII without any loss in meaning.
 | |
|   //  
 | |
|   OptionNumber = (UINT16) (BmCharToUint (VariableName[NumOff+0]) * 0x1000) 
 | |
|                + (UINT16) (BmCharToUint (VariableName[NumOff+1]) * 0x100)
 | |
|                + (UINT16) (BmCharToUint (VariableName[NumOff+2]) * 0x10)
 | |
|                + (UINT16) (BmCharToUint (VariableName[NumOff+3]) * 0x1);
 | |
| 
 | |
|   Status = EfiBootManagerInitializeLoadOption (
 | |
|              Option,
 | |
|              OptionNumber,
 | |
|              OptionType,
 | |
|              Attribute,
 | |
|              Description,
 | |
|              FilePath,
 | |
|              OptionalData,
 | |
|              OptionalDataSize
 | |
|              );
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
|   
 | |
|   FreePool (Variable);
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   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 *Option;
 | |
|   CHAR16                       OptionName[sizeof ("Driver####")];
 | |
|   UINT16                       OptionNumber;
 | |
| 
 | |
|   *OptionCount = 0;
 | |
| 
 | |
|   //
 | |
|   // Read the BootOrder, or DriverOrder variable.
 | |
|   //
 | |
|   GetEfiGlobalVariable2 (
 | |
|     (LoadOptionType == LoadOptionTypeBoot) ? L"BootOrder" : L"DriverOrder",
 | |
|     (VOID **) &OptionOrder,
 | |
|     &OptionOrderSize
 | |
|     );
 | |
|   if (OptionOrder == NULL) {
 | |
|     return NULL;
 | |
|   }
 | |
| 
 | |
|   *OptionCount = OptionOrderSize / sizeof (UINT16);
 | |
| 
 | |
|   Option = AllocatePool (*OptionCount * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));
 | |
|   ASSERT (Option != NULL);
 | |
| 
 | |
|   OptionIndex = 0;
 | |
|   for (Index = 0; Index < *OptionCount; Index++) {
 | |
|     OptionNumber = OptionOrder[Index];
 | |
|     if (LoadOptionType == LoadOptionTypeBoot) {
 | |
|       UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", OptionNumber);
 | |
|     } else {
 | |
|       UnicodeSPrint (OptionName, sizeof (OptionName), L"Driver%04x", OptionNumber);
 | |
|     }
 | |
| 
 | |
|     Status = EfiBootManagerVariableToLoadOption (OptionName, &Option[OptionIndex]);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       DEBUG ((EFI_D_INFO, "[Bds] %s doesn't exist - Update ****Order variable to remove the reference!!", OptionName));
 | |
|       EfiBootManagerDeleteLoadOptionVariable (OptionNumber, LoadOptionTypeBoot);
 | |
|     } else {
 | |
|       ASSERT (Option[OptionIndex].OptionNumber == OptionNumber);
 | |
|       OptionIndex++;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (OptionOrder != NULL) {
 | |
|     FreePool (OptionOrder);
 | |
|   }
 | |
| 
 | |
|   if (OptionIndex < *OptionCount) {
 | |
|     Option = ReallocatePool (
 | |
|                *OptionCount * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION),
 | |
|                OptionIndex * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION),
 | |
|                Option
 | |
|                );
 | |
|     ASSERT (Option != NULL);
 | |
|     *OptionCount = OptionIndex;
 | |
|   }
 | |
| 
 | |
|   return Option;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   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;
 | |
| }
 |