11e57a46299244793beb27e74be171d1540606999oliviermartin/** @file
21e57a46299244793beb27e74be171d1540606999oliviermartin*
3c0b2e4775dcb06d9016f17f5d22e6276d9b58397oliviermartin*  Copyright (c) 2011-2013, ARM Limited. All rights reserved.
41e57a46299244793beb27e74be171d1540606999oliviermartin*
51e57a46299244793beb27e74be171d1540606999oliviermartin*  This program and the accompanying materials
61e57a46299244793beb27e74be171d1540606999oliviermartin*  are licensed and made available under the terms and conditions of the BSD License
71e57a46299244793beb27e74be171d1540606999oliviermartin*  which accompanies this distribution.  The full text of the license may be found at
81e57a46299244793beb27e74be171d1540606999oliviermartin*  http://opensource.org/licenses/bsd-license.php
91e57a46299244793beb27e74be171d1540606999oliviermartin*
101e57a46299244793beb27e74be171d1540606999oliviermartin*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
111e57a46299244793beb27e74be171d1540606999oliviermartin*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
121e57a46299244793beb27e74be171d1540606999oliviermartin*
131e57a46299244793beb27e74be171d1540606999oliviermartin**/
141e57a46299244793beb27e74be171d1540606999oliviermartin
151e57a46299244793beb27e74be171d1540606999oliviermartin#include "BdsInternal.h"
161e57a46299244793beb27e74be171d1540606999oliviermartin
171e57a46299244793beb27e74be171d1540606999oliviermartinEFI_STATUS
181e57a46299244793beb27e74be171d1540606999oliviermartinBootOptionParseLoadOption (
19459823d9b24cd27e91d264dbd23c9ab699c34307Ard Biesheuvel  IN     EFI_LOAD_OPTION *EfiLoadOption,
201e57a46299244793beb27e74be171d1540606999oliviermartin  IN     UINTN           EfiLoadOptionSize,
211e57a46299244793beb27e74be171d1540606999oliviermartin  IN OUT BDS_LOAD_OPTION **BdsLoadOption
221e57a46299244793beb27e74be171d1540606999oliviermartin  )
231e57a46299244793beb27e74be171d1540606999oliviermartin{
241e57a46299244793beb27e74be171d1540606999oliviermartin  BDS_LOAD_OPTION *LoadOption;
251e57a46299244793beb27e74be171d1540606999oliviermartin  UINTN           DescriptionLength;
26459823d9b24cd27e91d264dbd23c9ab699c34307Ard Biesheuvel  UINTN           EfiLoadOptionPtr;
271e57a46299244793beb27e74be171d1540606999oliviermartin
281e57a46299244793beb27e74be171d1540606999oliviermartin  if (EfiLoadOption == NULL) {
291e57a46299244793beb27e74be171d1540606999oliviermartin    return EFI_INVALID_PARAMETER;
301e57a46299244793beb27e74be171d1540606999oliviermartin  }
311e57a46299244793beb27e74be171d1540606999oliviermartin
321e57a46299244793beb27e74be171d1540606999oliviermartin  if (EfiLoadOptionSize < sizeof(UINT32) + sizeof(UINT16) + sizeof(CHAR16) + sizeof(EFI_DEVICE_PATH_PROTOCOL)) {
331e57a46299244793beb27e74be171d1540606999oliviermartin    return EFI_BAD_BUFFER_SIZE;
341e57a46299244793beb27e74be171d1540606999oliviermartin  }
351e57a46299244793beb27e74be171d1540606999oliviermartin
361e57a46299244793beb27e74be171d1540606999oliviermartin  if (*BdsLoadOption == NULL) {
371e57a46299244793beb27e74be171d1540606999oliviermartin    LoadOption = (BDS_LOAD_OPTION*)AllocateZeroPool (sizeof(BDS_LOAD_OPTION));
381e57a46299244793beb27e74be171d1540606999oliviermartin    if (LoadOption == NULL) {
391e57a46299244793beb27e74be171d1540606999oliviermartin      return EFI_OUT_OF_RESOURCES;
401e57a46299244793beb27e74be171d1540606999oliviermartin    }
411e57a46299244793beb27e74be171d1540606999oliviermartin  } else {
421e57a46299244793beb27e74be171d1540606999oliviermartin    LoadOption = *BdsLoadOption;
431e57a46299244793beb27e74be171d1540606999oliviermartin  }
441e57a46299244793beb27e74be171d1540606999oliviermartin
45459823d9b24cd27e91d264dbd23c9ab699c34307Ard Biesheuvel  EfiLoadOptionPtr           = (UINTN)EfiLoadOption;
461e57a46299244793beb27e74be171d1540606999oliviermartin  LoadOption->LoadOption     = EfiLoadOption;
471e57a46299244793beb27e74be171d1540606999oliviermartin  LoadOption->LoadOptionSize = EfiLoadOptionSize;
481e57a46299244793beb27e74be171d1540606999oliviermartin
49459823d9b24cd27e91d264dbd23c9ab699c34307Ard Biesheuvel  LoadOption->Attributes         = *(UINT32*)EfiLoadOptionPtr;
50459823d9b24cd27e91d264dbd23c9ab699c34307Ard Biesheuvel  LoadOption->FilePathListLength = *(UINT16*)(EfiLoadOptionPtr + sizeof(UINT32));
51459823d9b24cd27e91d264dbd23c9ab699c34307Ard Biesheuvel  LoadOption->Description        = (CHAR16*)(EfiLoadOptionPtr + sizeof(UINT32) + sizeof(UINT16));
521e57a46299244793beb27e74be171d1540606999oliviermartin  DescriptionLength              = StrSize (LoadOption->Description);
53459823d9b24cd27e91d264dbd23c9ab699c34307Ard Biesheuvel  LoadOption->FilePathList       = (EFI_DEVICE_PATH_PROTOCOL*)(EfiLoadOptionPtr + sizeof(UINT32) + sizeof(UINT16) + DescriptionLength);
541e57a46299244793beb27e74be171d1540606999oliviermartin
551e57a46299244793beb27e74be171d1540606999oliviermartin  // If ((End of EfiLoadOptiony - Start of EfiLoadOption) == EfiLoadOptionSize) then No Optional Data
56459823d9b24cd27e91d264dbd23c9ab699c34307Ard Biesheuvel  if ((UINTN)((UINTN)LoadOption->FilePathList + LoadOption->FilePathListLength - EfiLoadOptionPtr) == EfiLoadOptionSize) {
571e57a46299244793beb27e74be171d1540606999oliviermartin    LoadOption->OptionalData     = NULL;
581e57a46299244793beb27e74be171d1540606999oliviermartin    LoadOption->OptionalDataSize = 0;
591e57a46299244793beb27e74be171d1540606999oliviermartin  } else {
601e57a46299244793beb27e74be171d1540606999oliviermartin    LoadOption->OptionalData     = (VOID*)((UINTN)(LoadOption->FilePathList) + LoadOption->FilePathListLength);
61459823d9b24cd27e91d264dbd23c9ab699c34307Ard Biesheuvel    LoadOption->OptionalDataSize = EfiLoadOptionSize - ((UINTN)LoadOption->OptionalData - EfiLoadOptionPtr);
621e57a46299244793beb27e74be171d1540606999oliviermartin  }
631e57a46299244793beb27e74be171d1540606999oliviermartin
641e57a46299244793beb27e74be171d1540606999oliviermartin  if (*BdsLoadOption == NULL) {
651e57a46299244793beb27e74be171d1540606999oliviermartin    *BdsLoadOption = LoadOption;
661e57a46299244793beb27e74be171d1540606999oliviermartin  }
671e57a46299244793beb27e74be171d1540606999oliviermartin
681e57a46299244793beb27e74be171d1540606999oliviermartin  return EFI_SUCCESS;
691e57a46299244793beb27e74be171d1540606999oliviermartin}
701e57a46299244793beb27e74be171d1540606999oliviermartin
711e57a46299244793beb27e74be171d1540606999oliviermartinEFI_STATUS
721e57a46299244793beb27e74be171d1540606999oliviermartinBootOptionFromLoadOptionVariable (
731e57a46299244793beb27e74be171d1540606999oliviermartin  IN  CHAR16*           BootVariableName,
741e57a46299244793beb27e74be171d1540606999oliviermartin  OUT BDS_LOAD_OPTION** BdsLoadOption
751e57a46299244793beb27e74be171d1540606999oliviermartin  )
761e57a46299244793beb27e74be171d1540606999oliviermartin{
771e57a46299244793beb27e74be171d1540606999oliviermartin  EFI_STATUS            Status;
78459823d9b24cd27e91d264dbd23c9ab699c34307Ard Biesheuvel  EFI_LOAD_OPTION       *EfiLoadOption;
791e57a46299244793beb27e74be171d1540606999oliviermartin  UINTN                 EfiLoadOptionSize;
801e57a46299244793beb27e74be171d1540606999oliviermartin
81c0b2e4775dcb06d9016f17f5d22e6276d9b58397oliviermartin  Status = GetGlobalEnvironmentVariable (BootVariableName, NULL, &EfiLoadOptionSize, (VOID**)&EfiLoadOption);
821e57a46299244793beb27e74be171d1540606999oliviermartin  if (!EFI_ERROR(Status)) {
831e57a46299244793beb27e74be171d1540606999oliviermartin    *BdsLoadOption = NULL;
841e57a46299244793beb27e74be171d1540606999oliviermartin    Status = BootOptionParseLoadOption (EfiLoadOption, EfiLoadOptionSize, BdsLoadOption);
851e57a46299244793beb27e74be171d1540606999oliviermartin  }
861e57a46299244793beb27e74be171d1540606999oliviermartin
871e57a46299244793beb27e74be171d1540606999oliviermartin  return Status;
881e57a46299244793beb27e74be171d1540606999oliviermartin}
891e57a46299244793beb27e74be171d1540606999oliviermartin
901e57a46299244793beb27e74be171d1540606999oliviermartinEFI_STATUS
911e57a46299244793beb27e74be171d1540606999oliviermartinBootOptionFromLoadOptionIndex (
921e57a46299244793beb27e74be171d1540606999oliviermartin  IN  UINT16            LoadOptionIndex,
931e57a46299244793beb27e74be171d1540606999oliviermartin  OUT BDS_LOAD_OPTION **BdsLoadOption
941e57a46299244793beb27e74be171d1540606999oliviermartin  )
951e57a46299244793beb27e74be171d1540606999oliviermartin{
961e57a46299244793beb27e74be171d1540606999oliviermartin  CHAR16        BootVariableName[9];
971e57a46299244793beb27e74be171d1540606999oliviermartin  EFI_STATUS    Status;
981e57a46299244793beb27e74be171d1540606999oliviermartin
991e57a46299244793beb27e74be171d1540606999oliviermartin  UnicodeSPrint (BootVariableName, 9 * sizeof(CHAR16), L"Boot%04X", LoadOptionIndex);
1001e57a46299244793beb27e74be171d1540606999oliviermartin
1011e57a46299244793beb27e74be171d1540606999oliviermartin  Status = BootOptionFromLoadOptionVariable (BootVariableName, BdsLoadOption);
1021e57a46299244793beb27e74be171d1540606999oliviermartin  if (!EFI_ERROR(Status)) {
1031e57a46299244793beb27e74be171d1540606999oliviermartin    (*BdsLoadOption)->LoadOptionIndex = LoadOptionIndex;
1041e57a46299244793beb27e74be171d1540606999oliviermartin  }
1051e57a46299244793beb27e74be171d1540606999oliviermartin
1061e57a46299244793beb27e74be171d1540606999oliviermartin  return Status;
1071e57a46299244793beb27e74be171d1540606999oliviermartin}
1081e57a46299244793beb27e74be171d1540606999oliviermartin
1091e57a46299244793beb27e74be171d1540606999oliviermartinEFI_STATUS
1101e57a46299244793beb27e74be171d1540606999oliviermartinBootOptionToLoadOptionVariable (
1111e57a46299244793beb27e74be171d1540606999oliviermartin  IN BDS_LOAD_OPTION*   BdsLoadOption
1121e57a46299244793beb27e74be171d1540606999oliviermartin  )
1131e57a46299244793beb27e74be171d1540606999oliviermartin{
1141e57a46299244793beb27e74be171d1540606999oliviermartin  EFI_STATUS                    Status;
1151e57a46299244793beb27e74be171d1540606999oliviermartin  UINTN                         DescriptionSize;
1161e57a46299244793beb27e74be171d1540606999oliviermartin  //UINT16                        FilePathListLength;
1171e57a46299244793beb27e74be171d1540606999oliviermartin  EFI_DEVICE_PATH_PROTOCOL*     DevicePathNode;
1181e57a46299244793beb27e74be171d1540606999oliviermartin  UINTN                         NodeLength;
1191e57a46299244793beb27e74be171d1540606999oliviermartin  UINT8*                        EfiLoadOptionPtr;
1201e57a46299244793beb27e74be171d1540606999oliviermartin  VOID*                         OldLoadOption;
1211e57a46299244793beb27e74be171d1540606999oliviermartin  CHAR16                        BootVariableName[9];
1221e57a46299244793beb27e74be171d1540606999oliviermartin  UINTN                         BootOrderSize;
1231e57a46299244793beb27e74be171d1540606999oliviermartin  UINT16*                       BootOrder;
1241e57a46299244793beb27e74be171d1540606999oliviermartin
1251e57a46299244793beb27e74be171d1540606999oliviermartin  // If we are overwriting an existent Boot Option then we have to free previously allocated memory
1261e57a46299244793beb27e74be171d1540606999oliviermartin  if (BdsLoadOption->LoadOptionSize > 0) {
1271e57a46299244793beb27e74be171d1540606999oliviermartin    OldLoadOption = BdsLoadOption->LoadOption;
1281e57a46299244793beb27e74be171d1540606999oliviermartin  } else {
1291e57a46299244793beb27e74be171d1540606999oliviermartin    OldLoadOption = NULL;
1301e57a46299244793beb27e74be171d1540606999oliviermartin
1311e57a46299244793beb27e74be171d1540606999oliviermartin    // If this function is called at the creation of the Boot Device entry (not at the update) the
1321e57a46299244793beb27e74be171d1540606999oliviermartin    // BootOption->LoadOptionSize must be zero then we get a new BootIndex for this entry
1331e57a46299244793beb27e74be171d1540606999oliviermartin    BdsLoadOption->LoadOptionIndex = BootOptionAllocateBootIndex ();
1341e57a46299244793beb27e74be171d1540606999oliviermartin
1351e57a46299244793beb27e74be171d1540606999oliviermartin    //TODO: Add to the the Boot Entry List
1361e57a46299244793beb27e74be171d1540606999oliviermartin  }
1371e57a46299244793beb27e74be171d1540606999oliviermartin
1381e57a46299244793beb27e74be171d1540606999oliviermartin  DescriptionSize = StrSize(BdsLoadOption->Description);
1391e57a46299244793beb27e74be171d1540606999oliviermartin
1401e57a46299244793beb27e74be171d1540606999oliviermartin  // Ensure the FilePathListLength information is correct
1411e57a46299244793beb27e74be171d1540606999oliviermartin  ASSERT (GetDevicePathSize (BdsLoadOption->FilePathList) == BdsLoadOption->FilePathListLength);
1421e57a46299244793beb27e74be171d1540606999oliviermartin
1431e57a46299244793beb27e74be171d1540606999oliviermartin  // Allocate the memory for the EFI Load Option
1441e57a46299244793beb27e74be171d1540606999oliviermartin  BdsLoadOption->LoadOptionSize = sizeof(UINT32) + sizeof(UINT16) + DescriptionSize + BdsLoadOption->FilePathListLength + BdsLoadOption->OptionalDataSize;
1451e57a46299244793beb27e74be171d1540606999oliviermartin
146459823d9b24cd27e91d264dbd23c9ab699c34307Ard Biesheuvel  BdsLoadOption->LoadOption = (EFI_LOAD_OPTION *)AllocateZeroPool (BdsLoadOption->LoadOptionSize);
1471e57a46299244793beb27e74be171d1540606999oliviermartin  if (BdsLoadOption->LoadOption == NULL) {
1481e57a46299244793beb27e74be171d1540606999oliviermartin    return EFI_OUT_OF_RESOURCES;
1491e57a46299244793beb27e74be171d1540606999oliviermartin  }
1501e57a46299244793beb27e74be171d1540606999oliviermartin
151459823d9b24cd27e91d264dbd23c9ab699c34307Ard Biesheuvel  EfiLoadOptionPtr = (UINT8 *) BdsLoadOption->LoadOption;
1521e57a46299244793beb27e74be171d1540606999oliviermartin
1531e57a46299244793beb27e74be171d1540606999oliviermartin  //
1541e57a46299244793beb27e74be171d1540606999oliviermartin  // Populate the EFI Load Option and BDS Boot Option structures
1551e57a46299244793beb27e74be171d1540606999oliviermartin  //
1561e57a46299244793beb27e74be171d1540606999oliviermartin
1571e57a46299244793beb27e74be171d1540606999oliviermartin  // Attributes fields
1581e57a46299244793beb27e74be171d1540606999oliviermartin  *(UINT32*)EfiLoadOptionPtr = BdsLoadOption->Attributes;
1591e57a46299244793beb27e74be171d1540606999oliviermartin  EfiLoadOptionPtr += sizeof(UINT32);
1601e57a46299244793beb27e74be171d1540606999oliviermartin
1611e57a46299244793beb27e74be171d1540606999oliviermartin  // FilePath List fields
1621e57a46299244793beb27e74be171d1540606999oliviermartin  *(UINT16*)EfiLoadOptionPtr = BdsLoadOption->FilePathListLength;
1631e57a46299244793beb27e74be171d1540606999oliviermartin  EfiLoadOptionPtr += sizeof(UINT16);
1641e57a46299244793beb27e74be171d1540606999oliviermartin
1651e57a46299244793beb27e74be171d1540606999oliviermartin  // Boot description fields
1661e57a46299244793beb27e74be171d1540606999oliviermartin  CopyMem (EfiLoadOptionPtr, BdsLoadOption->Description, DescriptionSize);
1671e57a46299244793beb27e74be171d1540606999oliviermartin  EfiLoadOptionPtr += DescriptionSize;
1681e57a46299244793beb27e74be171d1540606999oliviermartin
1691e57a46299244793beb27e74be171d1540606999oliviermartin  // File path fields
1701e57a46299244793beb27e74be171d1540606999oliviermartin  DevicePathNode = BdsLoadOption->FilePathList;
1711e57a46299244793beb27e74be171d1540606999oliviermartin  while (!IsDevicePathEndType (DevicePathNode)) {
1721e57a46299244793beb27e74be171d1540606999oliviermartin    NodeLength = DevicePathNodeLength(DevicePathNode);
1731e57a46299244793beb27e74be171d1540606999oliviermartin    CopyMem (EfiLoadOptionPtr, DevicePathNode, NodeLength);
1741e57a46299244793beb27e74be171d1540606999oliviermartin    EfiLoadOptionPtr += NodeLength;
1751e57a46299244793beb27e74be171d1540606999oliviermartin    DevicePathNode = NextDevicePathNode (DevicePathNode);
1761e57a46299244793beb27e74be171d1540606999oliviermartin  }
1771e57a46299244793beb27e74be171d1540606999oliviermartin
1781e57a46299244793beb27e74be171d1540606999oliviermartin  // Set the End Device Path Type
1791e57a46299244793beb27e74be171d1540606999oliviermartin  SetDevicePathEndNode (EfiLoadOptionPtr);
1801e57a46299244793beb27e74be171d1540606999oliviermartin  EfiLoadOptionPtr += sizeof(EFI_DEVICE_PATH);
1811e57a46299244793beb27e74be171d1540606999oliviermartin
1821e57a46299244793beb27e74be171d1540606999oliviermartin  // Fill the Optional Data
1831e57a46299244793beb27e74be171d1540606999oliviermartin  if (BdsLoadOption->OptionalDataSize > 0) {
1841e57a46299244793beb27e74be171d1540606999oliviermartin    CopyMem (EfiLoadOptionPtr, BdsLoadOption->OptionalData, BdsLoadOption->OptionalDataSize);
1851e57a46299244793beb27e74be171d1540606999oliviermartin  }
1861e57a46299244793beb27e74be171d1540606999oliviermartin
1871e57a46299244793beb27e74be171d1540606999oliviermartin  // Case where the fields have been updated
1881e57a46299244793beb27e74be171d1540606999oliviermartin  if (OldLoadOption) {
1891e57a46299244793beb27e74be171d1540606999oliviermartin    // Now, the old data has been copied to the new allocated packed structure, we need to update the pointers of BdsLoadOption
1901e57a46299244793beb27e74be171d1540606999oliviermartin    BootOptionParseLoadOption (BdsLoadOption->LoadOption, BdsLoadOption->LoadOptionSize, &BdsLoadOption);
1911e57a46299244793beb27e74be171d1540606999oliviermartin    // Free the old packed structure
1921e57a46299244793beb27e74be171d1540606999oliviermartin    FreePool (OldLoadOption);
1931e57a46299244793beb27e74be171d1540606999oliviermartin  }
1941e57a46299244793beb27e74be171d1540606999oliviermartin
1951e57a46299244793beb27e74be171d1540606999oliviermartin  // Create/Update Boot#### environment variable
1961e57a46299244793beb27e74be171d1540606999oliviermartin  UnicodeSPrint (BootVariableName, 9 * sizeof(CHAR16), L"Boot%04X", BdsLoadOption->LoadOptionIndex);
1971e57a46299244793beb27e74be171d1540606999oliviermartin  Status = gRT->SetVariable (
1981e57a46299244793beb27e74be171d1540606999oliviermartin      BootVariableName,
1991e57a46299244793beb27e74be171d1540606999oliviermartin      &gEfiGlobalVariableGuid,
2001e57a46299244793beb27e74be171d1540606999oliviermartin      EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
2011e57a46299244793beb27e74be171d1540606999oliviermartin      BdsLoadOption->LoadOptionSize,
2021e57a46299244793beb27e74be171d1540606999oliviermartin      BdsLoadOption->LoadOption
2031e57a46299244793beb27e74be171d1540606999oliviermartin      );
2041e57a46299244793beb27e74be171d1540606999oliviermartin
2051e57a46299244793beb27e74be171d1540606999oliviermartin  // When it is a new entry we must add the entry to the BootOrder
2061e57a46299244793beb27e74be171d1540606999oliviermartin  if (OldLoadOption == NULL) {
2071e57a46299244793beb27e74be171d1540606999oliviermartin    // Add the new Boot Index to the list
208c0b2e4775dcb06d9016f17f5d22e6276d9b58397oliviermartin    Status = GetGlobalEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder);
2091e57a46299244793beb27e74be171d1540606999oliviermartin    if (!EFI_ERROR(Status)) {
2101e57a46299244793beb27e74be171d1540606999oliviermartin      BootOrder = ReallocatePool (BootOrderSize, BootOrderSize + sizeof(UINT16), BootOrder);
2111e57a46299244793beb27e74be171d1540606999oliviermartin      // Add the new index at the end
2121e57a46299244793beb27e74be171d1540606999oliviermartin      BootOrder[BootOrderSize / sizeof(UINT16)] = BdsLoadOption->LoadOptionIndex;
2131e57a46299244793beb27e74be171d1540606999oliviermartin      BootOrderSize += sizeof(UINT16);
2141e57a46299244793beb27e74be171d1540606999oliviermartin    } else {
2151e57a46299244793beb27e74be171d1540606999oliviermartin      // BootOrder does not exist. Create it
2161e57a46299244793beb27e74be171d1540606999oliviermartin      BootOrderSize = sizeof(UINT16);
2171e57a46299244793beb27e74be171d1540606999oliviermartin      BootOrder = &(BdsLoadOption->LoadOptionIndex);
2181e57a46299244793beb27e74be171d1540606999oliviermartin    }
2191e57a46299244793beb27e74be171d1540606999oliviermartin
2201e57a46299244793beb27e74be171d1540606999oliviermartin    // Update (or Create) the BootOrder environment variable
2211e57a46299244793beb27e74be171d1540606999oliviermartin    gRT->SetVariable (
2221e57a46299244793beb27e74be171d1540606999oliviermartin        L"BootOrder",
2231e57a46299244793beb27e74be171d1540606999oliviermartin        &gEfiGlobalVariableGuid,
2241e57a46299244793beb27e74be171d1540606999oliviermartin        EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
2251e57a46299244793beb27e74be171d1540606999oliviermartin        BootOrderSize,
2261e57a46299244793beb27e74be171d1540606999oliviermartin        BootOrder
2271e57a46299244793beb27e74be171d1540606999oliviermartin        );
2281e57a46299244793beb27e74be171d1540606999oliviermartin    DEBUG((EFI_D_ERROR,"Create %s\n",BootVariableName));
2291e57a46299244793beb27e74be171d1540606999oliviermartin
230c0b2e4775dcb06d9016f17f5d22e6276d9b58397oliviermartin    // Free memory allocated by GetGlobalEnvironmentVariable
2311e57a46299244793beb27e74be171d1540606999oliviermartin    if (!EFI_ERROR(Status)) {
2321e57a46299244793beb27e74be171d1540606999oliviermartin      FreePool (BootOrder);
2331e57a46299244793beb27e74be171d1540606999oliviermartin    }
2341e57a46299244793beb27e74be171d1540606999oliviermartin  } else {
2351e57a46299244793beb27e74be171d1540606999oliviermartin    DEBUG((EFI_D_ERROR,"Update %s\n",BootVariableName));
2361e57a46299244793beb27e74be171d1540606999oliviermartin  }
2371e57a46299244793beb27e74be171d1540606999oliviermartin
2381e57a46299244793beb27e74be171d1540606999oliviermartin  return EFI_SUCCESS;
2391e57a46299244793beb27e74be171d1540606999oliviermartin}
2401e57a46299244793beb27e74be171d1540606999oliviermartin
2411e57a46299244793beb27e74be171d1540606999oliviermartinUINT16
2421e57a46299244793beb27e74be171d1540606999oliviermartinBootOptionAllocateBootIndex (
2431e57a46299244793beb27e74be171d1540606999oliviermartin  VOID
2441e57a46299244793beb27e74be171d1540606999oliviermartin  )
2451e57a46299244793beb27e74be171d1540606999oliviermartin{
2461e57a46299244793beb27e74be171d1540606999oliviermartin  EFI_STATUS        Status;
2471e57a46299244793beb27e74be171d1540606999oliviermartin  UINTN             Index;
2481e57a46299244793beb27e74be171d1540606999oliviermartin  UINT32            BootIndex;
2491e57a46299244793beb27e74be171d1540606999oliviermartin  UINT16            *BootOrder;
2501e57a46299244793beb27e74be171d1540606999oliviermartin  UINTN             BootOrderSize;
2511e57a46299244793beb27e74be171d1540606999oliviermartin  BOOLEAN           Found;
2521e57a46299244793beb27e74be171d1540606999oliviermartin
2531e57a46299244793beb27e74be171d1540606999oliviermartin  // Get the Boot Option Order from the environment variable
254c0b2e4775dcb06d9016f17f5d22e6276d9b58397oliviermartin  Status = GetGlobalEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder);
2551e57a46299244793beb27e74be171d1540606999oliviermartin  if (!EFI_ERROR(Status)) {
2561e57a46299244793beb27e74be171d1540606999oliviermartin    for (BootIndex = 0; BootIndex <= 0xFFFF; BootIndex++) {
2571e57a46299244793beb27e74be171d1540606999oliviermartin      Found = FALSE;
2581e57a46299244793beb27e74be171d1540606999oliviermartin      for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {
2591e57a46299244793beb27e74be171d1540606999oliviermartin        if (BootOrder[Index] == BootIndex) {
2601e57a46299244793beb27e74be171d1540606999oliviermartin          Found = TRUE;
2611e57a46299244793beb27e74be171d1540606999oliviermartin          break;
2621e57a46299244793beb27e74be171d1540606999oliviermartin        }
2631e57a46299244793beb27e74be171d1540606999oliviermartin      }
2641e57a46299244793beb27e74be171d1540606999oliviermartin      if (!Found) {
2651e57a46299244793beb27e74be171d1540606999oliviermartin        return BootIndex;
2661e57a46299244793beb27e74be171d1540606999oliviermartin      }
2671e57a46299244793beb27e74be171d1540606999oliviermartin    }
2681e57a46299244793beb27e74be171d1540606999oliviermartin    FreePool (BootOrder);
2691e57a46299244793beb27e74be171d1540606999oliviermartin  }
2701e57a46299244793beb27e74be171d1540606999oliviermartin  // Return the first index
2711e57a46299244793beb27e74be171d1540606999oliviermartin  return 0;
2721e57a46299244793beb27e74be171d1540606999oliviermartin}
273