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