Home | History | Annotate | Download | only in GenericBdsLib
      1 /** @file
      2   Misc BDS library function
      3 
      4 Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.<BR>
      5 This program and the accompanying materials
      6 are licensed and made available under the terms and conditions of the BSD License
      7 which accompanies this distribution.  The full text of the license may be found at
      8 http://opensource.org/licenses/bsd-license.php
      9 
     10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 #include "InternalBdsLib.h"
     16 
     17 
     18 #define MAX_STRING_LEN        200
     19 
     20 BOOLEAN   mFeaturerSwitch = TRUE;
     21 BOOLEAN   mResetRequired  = FALSE;
     22 
     23 extern UINT16 gPlatformBootTimeOutDefault;
     24 
     25 /**
     26   The function will go through the driver option link list, load and start
     27   every driver the driver option device path point to.
     28 
     29   @param  BdsDriverLists        The header of the current driver option link list
     30 
     31 **/
     32 VOID
     33 EFIAPI
     34 BdsLibLoadDrivers (
     35   IN LIST_ENTRY                   *BdsDriverLists
     36   )
     37 {
     38   EFI_STATUS                Status;
     39   LIST_ENTRY                *Link;
     40   BDS_COMMON_OPTION         *Option;
     41   EFI_HANDLE                ImageHandle;
     42   EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;
     43   UINTN                     ExitDataSize;
     44   CHAR16                    *ExitData;
     45   BOOLEAN                   ReconnectAll;
     46 
     47   ReconnectAll = FALSE;
     48 
     49   //
     50   // Process the driver option
     51   //
     52   for (Link = BdsDriverLists->ForwardLink; Link != BdsDriverLists; Link = Link->ForwardLink) {
     53     Option = CR (Link, BDS_COMMON_OPTION, Link, BDS_LOAD_OPTION_SIGNATURE);
     54 
     55     //
     56     // If a load option is not marked as LOAD_OPTION_ACTIVE,
     57     // the boot manager will not automatically load the option.
     58     //
     59     if (!IS_LOAD_OPTION_TYPE (Option->Attribute, LOAD_OPTION_ACTIVE)) {
     60       continue;
     61     }
     62 
     63     //
     64     // If a driver load option is marked as LOAD_OPTION_FORCE_RECONNECT,
     65     // then all of the EFI drivers in the system will be disconnected and
     66     // reconnected after the last driver load option is processed.
     67     //
     68     if (IS_LOAD_OPTION_TYPE (Option->Attribute, LOAD_OPTION_FORCE_RECONNECT)) {
     69       ReconnectAll = TRUE;
     70     }
     71 
     72     //
     73     // Make sure the driver path is connected.
     74     //
     75     BdsLibConnectDevicePath (Option->DevicePath);
     76 
     77     //
     78     // Load and start the image that Driver#### describes
     79     //
     80     Status = gBS->LoadImage (
     81                     FALSE,
     82                     gImageHandle,
     83                     Option->DevicePath,
     84                     NULL,
     85                     0,
     86                     &ImageHandle
     87                     );
     88 
     89     if (!EFI_ERROR (Status)) {
     90       gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo);
     91 
     92       //
     93       // Verify whether this image is a driver, if not,
     94       // exit it and continue to parse next load option
     95       //
     96       if (ImageInfo->ImageCodeType != EfiBootServicesCode && ImageInfo->ImageCodeType != EfiRuntimeServicesCode) {
     97         gBS->Exit (ImageHandle, EFI_INVALID_PARAMETER, 0, NULL);
     98         continue;
     99       }
    100 
    101       if (Option->LoadOptionsSize != 0) {
    102         ImageInfo->LoadOptionsSize  = Option->LoadOptionsSize;
    103         ImageInfo->LoadOptions      = Option->LoadOptions;
    104       }
    105       //
    106       // Before calling the image, enable the Watchdog Timer for
    107       // the 5 Minute period
    108       //
    109       gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);
    110 
    111       Status = gBS->StartImage (ImageHandle, &ExitDataSize, &ExitData);
    112       DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Driver Return Status = %r\n", Status));
    113 
    114       //
    115       // Clear the Watchdog Timer after the image returns
    116       //
    117       gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);
    118     }
    119   }
    120 
    121   //
    122   // Process the LOAD_OPTION_FORCE_RECONNECT driver option
    123   //
    124   if (ReconnectAll) {
    125     BdsLibDisconnectAllEfi ();
    126     BdsLibConnectAll ();
    127   }
    128 
    129 }
    130 
    131 /**
    132   Get the Option Number that does not used.
    133   Try to locate the specific option variable one by one utile find a free number.
    134 
    135   @param  VariableName          Indicate if the boot#### or driver#### option
    136 
    137   @return The Minimal Free Option Number
    138 
    139 **/
    140 UINT16
    141 BdsLibGetFreeOptionNumber (
    142   IN  CHAR16    *VariableName
    143   )
    144 {
    145   UINTN         Index;
    146   CHAR16        StrTemp[10];
    147   UINT16        *OptionBuffer;
    148   UINTN         OptionSize;
    149 
    150   //
    151   // Try to find the minimum free number from 0, 1, 2, 3....
    152   //
    153   Index = 0;
    154   do {
    155     if (*VariableName == 'B') {
    156       UnicodeSPrint (StrTemp, sizeof (StrTemp), L"Boot%04x", Index);
    157     } else {
    158       UnicodeSPrint (StrTemp, sizeof (StrTemp), L"Driver%04x", Index);
    159     }
    160     //
    161     // try if the option number is used
    162     //
    163     OptionBuffer = BdsLibGetVariableAndSize (
    164                      StrTemp,
    165                      &gEfiGlobalVariableGuid,
    166                      &OptionSize
    167                      );
    168     if (OptionBuffer == NULL) {
    169       break;
    170     }
    171     FreePool(OptionBuffer);
    172     Index++;
    173   } while (TRUE);
    174 
    175   return ((UINT16) Index);
    176 }
    177 
    178 
    179 /**
    180   This function will register the new boot#### or driver#### option base on
    181   the VariableName. The new registered boot#### or driver#### will be linked
    182   to BdsOptionList and also update to the VariableName. After the boot#### or
    183   driver#### updated, the BootOrder or DriverOrder will also be updated.
    184 
    185   @param  BdsOptionList         The header of the boot#### or driver#### link list
    186   @param  DevicePath            The device path which the boot#### or driver####
    187                                 option present
    188   @param  String                The description of the boot#### or driver####
    189   @param  VariableName          Indicate if the boot#### or driver#### option
    190 
    191   @retval EFI_SUCCESS           The boot#### or driver#### have been success
    192                                 registered
    193   @retval EFI_STATUS            Return the status of gRT->SetVariable ().
    194 
    195 **/
    196 EFI_STATUS
    197 EFIAPI
    198 BdsLibRegisterNewOption (
    199   IN  LIST_ENTRY                     *BdsOptionList,
    200   IN  EFI_DEVICE_PATH_PROTOCOL       *DevicePath,
    201   IN  CHAR16                         *String,
    202   IN  CHAR16                         *VariableName
    203   )
    204 {
    205   EFI_STATUS                Status;
    206   UINTN                     Index;
    207   UINT16                    RegisterOptionNumber;
    208   UINT16                    *TempOptionPtr;
    209   UINTN                     TempOptionSize;
    210   UINT16                    *OptionOrderPtr;
    211   VOID                      *OptionPtr;
    212   UINTN                     OptionSize;
    213   UINT8                     *TempPtr;
    214   EFI_DEVICE_PATH_PROTOCOL  *OptionDevicePath;
    215   CHAR16                    *Description;
    216   CHAR16                    OptionName[10];
    217   BOOLEAN                   UpdateDescription;
    218   UINT16                    BootOrderEntry;
    219   UINTN                     OrderItemNum;
    220 
    221   if (DevicePath == NULL) {
    222     return EFI_INVALID_PARAMETER;
    223   }
    224 
    225   OptionPtr             = NULL;
    226   OptionSize            = 0;
    227   TempPtr               = NULL;
    228   OptionDevicePath      = NULL;
    229   Description           = NULL;
    230   OptionOrderPtr        = NULL;
    231   UpdateDescription     = FALSE;
    232   Status                = EFI_SUCCESS;
    233   ZeroMem (OptionName, sizeof (OptionName));
    234 
    235   TempOptionSize = 0;
    236   TempOptionPtr = BdsLibGetVariableAndSize (
    237                     VariableName,
    238                     &gEfiGlobalVariableGuid,
    239                     &TempOptionSize
    240                     );
    241   //
    242   // Compare with current option variable if the previous option is set in global variable.
    243   //
    244   for (Index = 0; Index < TempOptionSize / sizeof (UINT16); Index++) {
    245     //
    246     // TempOptionPtr must not be NULL if we have non-zero TempOptionSize.
    247     //
    248     ASSERT (TempOptionPtr != NULL);
    249 
    250     if (*VariableName == 'B') {
    251       UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", TempOptionPtr[Index]);
    252     } else {
    253       UnicodeSPrint (OptionName, sizeof (OptionName), L"Driver%04x", TempOptionPtr[Index]);
    254     }
    255 
    256     OptionPtr = BdsLibGetVariableAndSize (
    257                   OptionName,
    258                   &gEfiGlobalVariableGuid,
    259                   &OptionSize
    260                   );
    261     if (OptionPtr == NULL) {
    262       continue;
    263     }
    264 
    265     //
    266     // Validate the variable.
    267     //
    268     if (!ValidateOption(OptionPtr, OptionSize)) {
    269       FreePool(OptionPtr);
    270       continue;
    271     }
    272 
    273     TempPtr         =   OptionPtr;
    274     TempPtr         +=  sizeof (UINT32) + sizeof (UINT16);
    275     Description     =   (CHAR16 *) TempPtr;
    276     TempPtr         +=  StrSize ((CHAR16 *) TempPtr);
    277     OptionDevicePath =  (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;
    278 
    279     //
    280     // Notes: the description may will change base on the GetStringToken
    281     //
    282     if (CompareMem (OptionDevicePath, DevicePath, GetDevicePathSize (OptionDevicePath)) == 0) {
    283       if (CompareMem (Description, String, StrSize (Description)) == 0) {
    284         //
    285         // Got the option, so just return
    286         //
    287         FreePool (OptionPtr);
    288         FreePool (TempOptionPtr);
    289         return EFI_SUCCESS;
    290       } else {
    291         //
    292         // Option description changed, need update.
    293         //
    294         UpdateDescription = TRUE;
    295         FreePool (OptionPtr);
    296         break;
    297       }
    298     }
    299 
    300     FreePool (OptionPtr);
    301   }
    302 
    303   OptionSize          = sizeof (UINT32) + sizeof (UINT16) + StrSize (String);
    304   OptionSize          += GetDevicePathSize (DevicePath);
    305   OptionPtr           = AllocateZeroPool (OptionSize);
    306   ASSERT (OptionPtr != NULL);
    307 
    308   TempPtr             = OptionPtr;
    309   *(UINT32 *) TempPtr = LOAD_OPTION_ACTIVE;
    310   TempPtr             += sizeof (UINT32);
    311   *(UINT16 *) TempPtr = (UINT16) GetDevicePathSize (DevicePath);
    312   TempPtr             += sizeof (UINT16);
    313   CopyMem (TempPtr, String, StrSize (String));
    314   TempPtr             += StrSize (String);
    315   CopyMem (TempPtr, DevicePath, GetDevicePathSize (DevicePath));
    316 
    317   if (UpdateDescription) {
    318     //
    319     // The number in option#### to be updated.
    320     // In this case, we must have non-NULL TempOptionPtr.
    321     //
    322     ASSERT (TempOptionPtr != NULL);
    323     RegisterOptionNumber = TempOptionPtr[Index];
    324   } else {
    325     //
    326     // The new option#### number
    327     //
    328     RegisterOptionNumber = BdsLibGetFreeOptionNumber(VariableName);
    329   }
    330 
    331   if (*VariableName == 'B') {
    332     UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", RegisterOptionNumber);
    333   } else {
    334     UnicodeSPrint (OptionName, sizeof (OptionName), L"Driver%04x", RegisterOptionNumber);
    335   }
    336 
    337   Status = gRT->SetVariable (
    338                   OptionName,
    339                   &gEfiGlobalVariableGuid,
    340                   EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
    341                   OptionSize,
    342                   OptionPtr
    343                   );
    344   //
    345   // Return if only need to update a changed description or fail to set option.
    346   //
    347   if (EFI_ERROR (Status) || UpdateDescription) {
    348     FreePool (OptionPtr);
    349     if (TempOptionPtr != NULL) {
    350       FreePool (TempOptionPtr);
    351     }
    352     return Status;
    353   }
    354 
    355   FreePool (OptionPtr);
    356 
    357   //
    358   // Update the option order variable
    359   //
    360 
    361   //
    362   // If no option order
    363   //
    364   if (TempOptionSize == 0) {
    365     BootOrderEntry = 0;
    366     Status = gRT->SetVariable (
    367                     VariableName,
    368                     &gEfiGlobalVariableGuid,
    369                     EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
    370                     sizeof (UINT16),
    371                     &BootOrderEntry
    372                     );
    373     if (TempOptionPtr != NULL) {
    374       FreePool (TempOptionPtr);
    375     }
    376     return Status;
    377   }
    378 
    379   //
    380   // TempOptionPtr must not be NULL if TempOptionSize is not zero.
    381   //
    382   ASSERT (TempOptionPtr != NULL);
    383   //
    384   // Append the new option number to the original option order
    385   //
    386   OrderItemNum = (TempOptionSize / sizeof (UINT16)) + 1 ;
    387   OptionOrderPtr = AllocateZeroPool ( OrderItemNum * sizeof (UINT16));
    388   ASSERT (OptionOrderPtr!= NULL);
    389   CopyMem (OptionOrderPtr, TempOptionPtr, (OrderItemNum - 1) * sizeof (UINT16));
    390 
    391   OptionOrderPtr[Index] = RegisterOptionNumber;
    392 
    393   Status = gRT->SetVariable (
    394                   VariableName,
    395                   &gEfiGlobalVariableGuid,
    396                   EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
    397                   OrderItemNum * sizeof (UINT16),
    398                   OptionOrderPtr
    399                   );
    400   FreePool (TempOptionPtr);
    401   FreePool (OptionOrderPtr);
    402 
    403   return Status;
    404 }
    405 
    406 /**
    407   Returns the size of a device path in bytes.
    408 
    409   This function returns the size, in bytes, of the device path data structure
    410   specified by DevicePath including the end of device path node. If DevicePath
    411   is NULL, then 0 is returned. If the length of the device path is bigger than
    412   MaxSize, also return 0 to indicate this is an invalidate device path.
    413 
    414   @param  DevicePath         A pointer to a device path data structure.
    415   @param  MaxSize            Max valid device path size. If big than this size,
    416                              return error.
    417 
    418   @retval 0                  An invalid device path.
    419   @retval Others             The size of a device path in bytes.
    420 
    421 **/
    422 UINTN
    423 GetDevicePathSizeEx (
    424   IN CONST EFI_DEVICE_PATH_PROTOCOL  *DevicePath,
    425   IN UINTN                           MaxSize
    426   )
    427 {
    428   UINTN  Size;
    429   UINTN  NodeSize;
    430 
    431   if (DevicePath == NULL) {
    432     return 0;
    433   }
    434 
    435   //
    436   // Search for the end of the device path structure
    437   //
    438   Size = 0;
    439   while (!IsDevicePathEnd (DevicePath)) {
    440     NodeSize = DevicePathNodeLength (DevicePath);
    441     if (NodeSize < END_DEVICE_PATH_LENGTH) {
    442       return 0;
    443     }
    444     Size += NodeSize;
    445     if (Size > MaxSize) {
    446       return 0;
    447     }
    448     DevicePath = NextDevicePathNode (DevicePath);
    449   }
    450   Size += DevicePathNodeLength (DevicePath);
    451   if (Size > MaxSize) {
    452     return 0;
    453   }
    454 
    455   return Size;
    456 }
    457 
    458 /**
    459   Returns the length of a Null-terminated Unicode string. If the length is
    460   bigger than MaxStringLen, return length 0 to indicate that this is an
    461   invalidate string.
    462 
    463   This function returns the byte length of Unicode characters in the Null-terminated
    464   Unicode string specified by String.
    465 
    466   If String is NULL, then ASSERT().
    467   If String is not aligned on a 16-bit boundary, then ASSERT().
    468 
    469   @param  String           A pointer to a Null-terminated Unicode string.
    470   @param  MaxStringLen     Max string len in this string.
    471 
    472   @retval 0                An invalid string.
    473   @retval Others           The length of String.
    474 
    475 **/
    476 UINTN
    477 StrSizeEx (
    478   IN      CONST CHAR16              *String,
    479   IN      UINTN                     MaxStringLen
    480   )
    481 {
    482   UINTN                             Length;
    483 
    484   ASSERT (String != NULL && MaxStringLen != 0);
    485   ASSERT (((UINTN) String & BIT0) == 0);
    486 
    487   for (Length = 0; *String != L'\0' && MaxStringLen != Length; String++, Length+=2);
    488 
    489   if (*String != L'\0' && MaxStringLen == Length) {
    490     return 0;
    491   }
    492 
    493   return Length + 2;
    494 }
    495 
    496 /**
    497   Validate the EFI Boot#### variable (VendorGuid/Name)
    498 
    499   @param  Variable              Boot#### variable data.
    500   @param  VariableSize          Returns the size of the EFI variable that was read
    501 
    502   @retval TRUE                  The variable data is correct.
    503   @retval FALSE                 The variable data is corrupted.
    504 
    505 **/
    506 BOOLEAN
    507 ValidateOption (
    508   UINT8                     *Variable,
    509   UINTN                     VariableSize
    510   )
    511 {
    512   UINT16                    FilePathSize;
    513   UINT8                     *TempPtr;
    514   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
    515   UINTN                     TempSize;
    516 
    517   if (VariableSize <= sizeof (UINT16) + sizeof (UINT32)) {
    518     return FALSE;
    519   }
    520 
    521   //
    522   // Skip the option attribute
    523   //
    524   TempPtr    = Variable;
    525   TempPtr   += sizeof (UINT32);
    526 
    527   //
    528   // Get the option's device path size
    529   //
    530   FilePathSize  = *(UINT16 *) TempPtr;
    531   TempPtr      += sizeof (UINT16);
    532 
    533   //
    534   // Get the option's description string size
    535   //
    536   TempSize = StrSizeEx ((CHAR16 *) TempPtr, VariableSize - sizeof (UINT16) - sizeof (UINT32));
    537   TempPtr += TempSize;
    538 
    539   //
    540   // Get the option's device path
    541   //
    542   DevicePath =  (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;
    543   TempPtr   += FilePathSize;
    544 
    545   //
    546   // Validation boot option variable.
    547   //
    548   if ((FilePathSize == 0) || (TempSize == 0)) {
    549     return FALSE;
    550   }
    551 
    552   if (TempSize + FilePathSize + sizeof (UINT16) + sizeof (UINT32) > VariableSize) {
    553     return FALSE;
    554   }
    555 
    556   return (BOOLEAN) (GetDevicePathSizeEx (DevicePath, FilePathSize) != 0);
    557 }
    558 
    559 /**
    560   Convert a single character to number.
    561   It assumes the input Char is in the scope of L'0' ~ L'9' and L'A' ~ L'F'
    562 
    563   @param Char    The input char which need to change to a hex number.
    564 
    565 **/
    566 UINTN
    567 CharToUint (
    568   IN CHAR16                           Char
    569   )
    570 {
    571   if ((Char >= L'0') && (Char <= L'9')) {
    572     return (UINTN) (Char - L'0');
    573   }
    574 
    575   if ((Char >= L'A') && (Char <= L'F')) {
    576     return (UINTN) (Char - L'A' + 0xA);
    577   }
    578 
    579   ASSERT (FALSE);
    580   return 0;
    581 }
    582 
    583 /**
    584   Build the boot#### or driver#### option from the VariableName, the
    585   build boot#### or driver#### will also be linked to BdsCommonOptionList.
    586 
    587   @param  BdsCommonOptionList   The header of the boot#### or driver#### option
    588                                 link list
    589   @param  VariableName          EFI Variable name indicate if it is boot#### or
    590                                 driver####
    591 
    592   @retval BDS_COMMON_OPTION     Get the option just been created
    593   @retval NULL                  Failed to get the new option
    594 
    595 **/
    596 BDS_COMMON_OPTION *
    597 EFIAPI
    598 BdsLibVariableToOption (
    599   IN OUT LIST_ENTRY                   *BdsCommonOptionList,
    600   IN  CHAR16                          *VariableName
    601   )
    602 {
    603   UINT32                    Attribute;
    604   UINT16                    FilePathSize;
    605   UINT8                     *Variable;
    606   UINT8                     *TempPtr;
    607   UINTN                     VariableSize;
    608   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
    609   BDS_COMMON_OPTION         *Option;
    610   VOID                      *LoadOptions;
    611   UINT32                    LoadOptionsSize;
    612   CHAR16                    *Description;
    613   UINT8                     NumOff;
    614 
    615   //
    616   // Read the variable. We will never free this data.
    617   //
    618   Variable = BdsLibGetVariableAndSize (
    619               VariableName,
    620               &gEfiGlobalVariableGuid,
    621               &VariableSize
    622               );
    623   if (Variable == NULL) {
    624     return NULL;
    625   }
    626 
    627   //
    628   // Validate Boot#### variable data.
    629   //
    630   if (!ValidateOption(Variable, VariableSize)) {
    631     FreePool (Variable);
    632     return NULL;
    633   }
    634 
    635   //
    636   // Notes: careful defined the variable of Boot#### or
    637   // Driver####, consider use some macro to abstract the code
    638   //
    639   //
    640   // Get the option attribute
    641   //
    642   TempPtr   =  Variable;
    643   Attribute =  *(UINT32 *) Variable;
    644   TempPtr   += sizeof (UINT32);
    645 
    646   //
    647   // Get the option's device path size
    648   //
    649   FilePathSize =  *(UINT16 *) TempPtr;
    650   TempPtr      += sizeof (UINT16);
    651 
    652   //
    653   // Get the option's description string
    654   //
    655   Description = (CHAR16 *) TempPtr;
    656 
    657   //
    658   // Get the option's description string size
    659   //
    660   TempPtr += StrSize((CHAR16 *) TempPtr);
    661 
    662   //
    663   // Get the option's device path
    664   //
    665   DevicePath =  (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;
    666   TempPtr    += FilePathSize;
    667 
    668   //
    669   // Get load opion data.
    670   //
    671   LoadOptions     = TempPtr;
    672   LoadOptionsSize = (UINT32) (VariableSize - (UINTN) (TempPtr - Variable));
    673 
    674   //
    675   // The Console variables may have multiple device paths, so make
    676   // an Entry for each one.
    677   //
    678   Option = AllocateZeroPool (sizeof (BDS_COMMON_OPTION));
    679   if (Option == NULL) {
    680     FreePool (Variable);
    681     return NULL;
    682   }
    683 
    684   Option->Signature   = BDS_LOAD_OPTION_SIGNATURE;
    685   Option->DevicePath  = AllocateZeroPool (GetDevicePathSize (DevicePath));
    686   ASSERT(Option->DevicePath != NULL);
    687   CopyMem (Option->DevicePath, DevicePath, GetDevicePathSize (DevicePath));
    688 
    689   Option->Attribute   = Attribute;
    690   Option->Description = AllocateZeroPool (StrSize (Description));
    691   ASSERT(Option->Description != NULL);
    692   CopyMem (Option->Description, Description, StrSize (Description));
    693 
    694   Option->LoadOptions = AllocateZeroPool (LoadOptionsSize);
    695   ASSERT(Option->LoadOptions != NULL);
    696   CopyMem (Option->LoadOptions, LoadOptions, LoadOptionsSize);
    697   Option->LoadOptionsSize = LoadOptionsSize;
    698 
    699   //
    700   // Get the value from VariableName Unicode string
    701   // since the ISO standard assumes ASCII equivalent abbreviations, we can be safe in converting this
    702   // Unicode stream to ASCII without any loss in meaning.
    703   //
    704   if (*VariableName == 'B') {
    705     NumOff = (UINT8) (sizeof (L"Boot") / sizeof (CHAR16) - 1);
    706     Option->BootCurrent = (UINT16) (CharToUint (VariableName[NumOff+0]) * 0x1000)
    707                + (UINT16) (CharToUint (VariableName[NumOff+1]) * 0x100)
    708                + (UINT16) (CharToUint (VariableName[NumOff+2]) * 0x10)
    709                + (UINT16) (CharToUint (VariableName[NumOff+3]) * 0x1);
    710   }
    711   InsertTailList (BdsCommonOptionList, &Option->Link);
    712   FreePool (Variable);
    713   return Option;
    714 }
    715 
    716 /**
    717   Process BootOrder, or DriverOrder variables, by calling
    718   BdsLibVariableToOption () for each UINT16 in the variables.
    719 
    720   @param  BdsCommonOptionList   The header of the option list base on variable
    721                                 VariableName
    722   @param  VariableName          EFI Variable name indicate the BootOrder or
    723                                 DriverOrder
    724 
    725   @retval EFI_SUCCESS           Success create the boot option or driver option
    726                                 list
    727   @retval EFI_OUT_OF_RESOURCES  Failed to get the boot option or driver option list
    728 
    729 **/
    730 EFI_STATUS
    731 EFIAPI
    732 BdsLibBuildOptionFromVar (
    733   IN  LIST_ENTRY                      *BdsCommonOptionList,
    734   IN  CHAR16                          *VariableName
    735   )
    736 {
    737   UINT16            *OptionOrder;
    738   UINTN             OptionOrderSize;
    739   UINTN             Index;
    740   BDS_COMMON_OPTION *Option;
    741   CHAR16            OptionName[20];
    742 
    743   //
    744   // Zero Buffer in order to get all BOOT#### variables
    745   //
    746   ZeroMem (OptionName, sizeof (OptionName));
    747 
    748   //
    749   // Read the BootOrder, or DriverOrder variable.
    750   //
    751   OptionOrder = BdsLibGetVariableAndSize (
    752                   VariableName,
    753                   &gEfiGlobalVariableGuid,
    754                   &OptionOrderSize
    755                   );
    756   if (OptionOrder == NULL) {
    757     return EFI_OUT_OF_RESOURCES;
    758   }
    759 
    760   for (Index = 0; Index < OptionOrderSize / sizeof (UINT16); Index++) {
    761     if (*VariableName == 'B') {
    762       UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", OptionOrder[Index]);
    763     } else {
    764       UnicodeSPrint (OptionName, sizeof (OptionName), L"Driver%04x", OptionOrder[Index]);
    765     }
    766 
    767     Option              = BdsLibVariableToOption (BdsCommonOptionList, OptionName);
    768     if (Option != NULL) {
    769       Option->BootCurrent = OptionOrder[Index];
    770     }
    771   }
    772 
    773   FreePool (OptionOrder);
    774 
    775   return EFI_SUCCESS;
    776 }
    777 
    778 /**
    779   Get boot mode by looking up configuration table and parsing HOB list
    780 
    781   @param  BootMode              Boot mode from PEI handoff HOB.
    782 
    783   @retval EFI_SUCCESS           Successfully get boot mode
    784 
    785 **/
    786 EFI_STATUS
    787 EFIAPI
    788 BdsLibGetBootMode (
    789   OUT EFI_BOOT_MODE       *BootMode
    790   )
    791 {
    792   *BootMode = GetBootModeHob ();
    793 
    794   return EFI_SUCCESS;
    795 }
    796 
    797 /**
    798   Read the EFI variable (VendorGuid/Name) and return a dynamically allocated
    799   buffer, and the size of the buffer. If failure return NULL.
    800 
    801   @param  Name                  String part of EFI variable name
    802   @param  VendorGuid            GUID part of EFI variable name
    803   @param  VariableSize          Returns the size of the EFI variable that was read
    804 
    805   @return                       Dynamically allocated memory that contains a copy of the EFI variable
    806                                 Caller is responsible freeing the buffer.
    807   @retval NULL                  Variable was not read
    808 
    809 **/
    810 VOID *
    811 EFIAPI
    812 BdsLibGetVariableAndSize (
    813   IN  CHAR16              *Name,
    814   IN  EFI_GUID            *VendorGuid,
    815   OUT UINTN               *VariableSize
    816   )
    817 {
    818   EFI_STATUS  Status;
    819   UINTN       BufferSize;
    820   VOID        *Buffer;
    821 
    822   Buffer = NULL;
    823 
    824   //
    825   // Pass in a zero size buffer to find the required buffer size.
    826   //
    827   BufferSize  = 0;
    828   Status      = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer);
    829   if (Status == EFI_BUFFER_TOO_SMALL) {
    830     //
    831     // Allocate the buffer to return
    832     //
    833     Buffer = AllocateZeroPool (BufferSize);
    834     if (Buffer == NULL) {
    835       *VariableSize = 0;
    836       return NULL;
    837     }
    838     //
    839     // Read variable into the allocated buffer.
    840     //
    841     Status = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer);
    842     if (EFI_ERROR (Status)) {
    843       FreePool (Buffer);
    844       BufferSize = 0;
    845       Buffer     = NULL;
    846     }
    847   }
    848 
    849   ASSERT (((Buffer == NULL) && (BufferSize == 0)) ||
    850           ((Buffer != NULL) && (BufferSize != 0))
    851           );
    852   *VariableSize = BufferSize;
    853   return Buffer;
    854 }
    855 
    856 /**
    857   Delete the instance in Multi which matches partly with Single instance
    858 
    859   @param  Multi                 A pointer to a multi-instance device path data
    860                                 structure.
    861   @param  Single                A pointer to a single-instance device path data
    862                                 structure.
    863 
    864   @return This function will remove the device path instances in Multi which partly
    865           match with the Single, and return the result device path. If there is no
    866           remaining device path as a result, this function will return NULL.
    867 
    868 **/
    869 EFI_DEVICE_PATH_PROTOCOL *
    870 EFIAPI
    871 BdsLibDelPartMatchInstance (
    872   IN     EFI_DEVICE_PATH_PROTOCOL  *Multi,
    873   IN     EFI_DEVICE_PATH_PROTOCOL  *Single
    874   )
    875 {
    876   EFI_DEVICE_PATH_PROTOCOL  *Instance;
    877   EFI_DEVICE_PATH_PROTOCOL  *NewDevicePath;
    878   EFI_DEVICE_PATH_PROTOCOL  *TempNewDevicePath;
    879   UINTN                     InstanceSize;
    880   UINTN                     SingleDpSize;
    881   UINTN                     Size;
    882 
    883   NewDevicePath     = NULL;
    884   TempNewDevicePath = NULL;
    885 
    886   if (Multi == NULL || Single == NULL) {
    887     return Multi;
    888   }
    889 
    890   Instance        =  GetNextDevicePathInstance (&Multi, &InstanceSize);
    891   SingleDpSize    =  GetDevicePathSize (Single) - END_DEVICE_PATH_LENGTH;
    892   InstanceSize    -= END_DEVICE_PATH_LENGTH;
    893 
    894   while (Instance != NULL) {
    895 
    896     Size = (SingleDpSize < InstanceSize) ? SingleDpSize : InstanceSize;
    897 
    898     if ((CompareMem (Instance, Single, Size) != 0)) {
    899       //
    900       // Append the device path instance which does not match with Single
    901       //
    902       TempNewDevicePath = NewDevicePath;
    903       NewDevicePath = AppendDevicePathInstance (NewDevicePath, Instance);
    904       if (TempNewDevicePath != NULL) {
    905         FreePool(TempNewDevicePath);
    906       }
    907     }
    908     FreePool(Instance);
    909     Instance = GetNextDevicePathInstance (&Multi, &InstanceSize);
    910     InstanceSize  -= END_DEVICE_PATH_LENGTH;
    911   }
    912 
    913   return NewDevicePath;
    914 }
    915 
    916 /**
    917   Function compares a device path data structure to that of all the nodes of a
    918   second device path instance.
    919 
    920   @param  Multi                 A pointer to a multi-instance device path data
    921                                 structure.
    922   @param  Single                A pointer to a single-instance device path data
    923                                 structure.
    924 
    925   @retval TRUE                  If the Single device path is contained within Multi device path.
    926   @retval FALSE                 The Single device path is not match within Multi device path.
    927 
    928 **/
    929 BOOLEAN
    930 EFIAPI
    931 BdsLibMatchDevicePaths (
    932   IN  EFI_DEVICE_PATH_PROTOCOL  *Multi,
    933   IN  EFI_DEVICE_PATH_PROTOCOL  *Single
    934   )
    935 {
    936   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
    937   EFI_DEVICE_PATH_PROTOCOL  *DevicePathInst;
    938   UINTN                     Size;
    939 
    940   if (Multi == NULL || Single  == NULL) {
    941     return FALSE;
    942   }
    943 
    944   DevicePath      = Multi;
    945   DevicePathInst  = GetNextDevicePathInstance (&DevicePath, &Size);
    946 
    947   //
    948   // Search for the match of 'Single' in 'Multi'
    949   //
    950   while (DevicePathInst != NULL) {
    951     //
    952     // If the single device path is found in multiple device paths,
    953     // return success
    954     //
    955     if (CompareMem (Single, DevicePathInst, Size) == 0) {
    956       FreePool (DevicePathInst);
    957       return TRUE;
    958     }
    959 
    960     FreePool (DevicePathInst);
    961     DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);
    962   }
    963 
    964   return FALSE;
    965 }
    966 
    967 /**
    968   This function prints a series of strings.
    969 
    970   @param  ConOut                Pointer to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
    971   @param  ...                   A variable argument list containing series of
    972                                 strings, the last string must be NULL.
    973 
    974   @retval EFI_SUCCESS           Success print out the string using ConOut.
    975   @retval EFI_STATUS            Return the status of the ConOut->OutputString ().
    976 
    977 **/
    978 EFI_STATUS
    979 EFIAPI
    980 BdsLibOutputStrings (
    981   IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL   *ConOut,
    982   ...
    983   )
    984 {
    985   VA_LIST     Args;
    986   EFI_STATUS  Status;
    987   CHAR16      *String;
    988 
    989   Status = EFI_SUCCESS;
    990   VA_START (Args, ConOut);
    991 
    992   while (!EFI_ERROR (Status)) {
    993     //
    994     // If String is NULL, then it's the end of the list
    995     //
    996     String = VA_ARG (Args, CHAR16 *);
    997     if (String == NULL) {
    998       break;
    999     }
   1000 
   1001     Status = ConOut->OutputString (ConOut, String);
   1002 
   1003     if (EFI_ERROR (Status)) {
   1004       break;
   1005     }
   1006   }
   1007 
   1008   VA_END(Args);
   1009   return Status;
   1010 }
   1011 
   1012 //
   1013 //  Following are BDS Lib functions which contain all the code about setup browser reset reminder feature.
   1014 //  Setup Browser reset reminder feature is that an reset reminder will be given before user leaves the setup browser  if
   1015 //  user change any option setting which needs a reset to be effective, and  the reset will be applied according to  the user selection.
   1016 //
   1017 
   1018 
   1019 /**
   1020   Enable the setup browser reset reminder feature.
   1021   This routine is used in platform tip. If the platform policy need the feature, use the routine to enable it.
   1022 
   1023 **/
   1024 VOID
   1025 EFIAPI
   1026 EnableResetReminderFeature (
   1027   VOID
   1028   )
   1029 {
   1030   mFeaturerSwitch = TRUE;
   1031 }
   1032 
   1033 
   1034 /**
   1035   Disable the setup browser reset reminder feature.
   1036   This routine is used in platform tip. If the platform policy do not want the feature, use the routine to disable it.
   1037 
   1038 **/
   1039 VOID
   1040 EFIAPI
   1041 DisableResetReminderFeature (
   1042   VOID
   1043   )
   1044 {
   1045   mFeaturerSwitch = FALSE;
   1046 }
   1047 
   1048 
   1049 /**
   1050   Record the info that  a reset is required.
   1051   A  module boolean variable is used to record whether a reset is required.
   1052 
   1053 **/
   1054 VOID
   1055 EFIAPI
   1056 EnableResetRequired (
   1057   VOID
   1058   )
   1059 {
   1060   mResetRequired = TRUE;
   1061 }
   1062 
   1063 
   1064 /**
   1065   Record the info that  no reset is required.
   1066   A  module boolean variable is used to record whether a reset is required.
   1067 
   1068 **/
   1069 VOID
   1070 EFIAPI
   1071 DisableResetRequired (
   1072   VOID
   1073   )
   1074 {
   1075   mResetRequired = FALSE;
   1076 }
   1077 
   1078 
   1079 /**
   1080   Check whether platform policy enable the reset reminder feature. The default is enabled.
   1081 
   1082 **/
   1083 BOOLEAN
   1084 EFIAPI
   1085 IsResetReminderFeatureEnable (
   1086   VOID
   1087   )
   1088 {
   1089   return mFeaturerSwitch;
   1090 }
   1091 
   1092 
   1093 /**
   1094   Check if  user changed any option setting which needs a system reset to be effective.
   1095 
   1096 **/
   1097 BOOLEAN
   1098 EFIAPI
   1099 IsResetRequired (
   1100   VOID
   1101   )
   1102 {
   1103   return mResetRequired;
   1104 }
   1105 
   1106 
   1107 /**
   1108   Check whether a reset is needed, and finish the reset reminder feature.
   1109   If a reset is needed, Popup a menu to notice user, and finish the feature
   1110   according to the user selection.
   1111 
   1112 **/
   1113 VOID
   1114 EFIAPI
   1115 SetupResetReminder (
   1116   VOID
   1117   )
   1118 {
   1119   EFI_INPUT_KEY                 Key;
   1120   CHAR16                        *StringBuffer1;
   1121   CHAR16                        *StringBuffer2;
   1122 
   1123 
   1124   //
   1125   //check any reset required change is applied? if yes, reset system
   1126   //
   1127   if (IsResetReminderFeatureEnable ()) {
   1128     if (IsResetRequired ()) {
   1129 
   1130       StringBuffer1 = AllocateZeroPool (MAX_STRING_LEN * sizeof (CHAR16));
   1131       ASSERT (StringBuffer1 != NULL);
   1132       StringBuffer2 = AllocateZeroPool (MAX_STRING_LEN * sizeof (CHAR16));
   1133       ASSERT (StringBuffer2 != NULL);
   1134       StrCpy (StringBuffer1, L"Configuration changed. Reset to apply it Now.");
   1135       StrCpy (StringBuffer2, L"Press ENTER to reset");
   1136       //
   1137       // Popup a menu to notice user
   1138       //
   1139       do {
   1140         CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, StringBuffer1, StringBuffer2, NULL);
   1141       } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
   1142 
   1143       FreePool (StringBuffer1);
   1144       FreePool (StringBuffer2);
   1145 
   1146       gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);
   1147     }
   1148   }
   1149 }
   1150 
   1151 /**
   1152   Get the headers (dos, image, optional header) from an image
   1153 
   1154   @param  Device                SimpleFileSystem device handle
   1155   @param  FileName              File name for the image
   1156   @param  DosHeader             Pointer to dos header
   1157   @param  Hdr                   The buffer in which to return the PE32, PE32+, or TE header.
   1158 
   1159   @retval EFI_SUCCESS           Successfully get the machine type.
   1160   @retval EFI_NOT_FOUND         The file is not found.
   1161   @retval EFI_LOAD_ERROR        File is not a valid image file.
   1162 
   1163 **/
   1164 EFI_STATUS
   1165 EFIAPI
   1166 BdsLibGetImageHeader (
   1167   IN  EFI_HANDLE                  Device,
   1168   IN  CHAR16                      *FileName,
   1169   OUT EFI_IMAGE_DOS_HEADER        *DosHeader,
   1170   OUT EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION   Hdr
   1171   )
   1172 {
   1173   EFI_STATUS                       Status;
   1174   EFI_SIMPLE_FILE_SYSTEM_PROTOCOL  *Volume;
   1175   EFI_FILE_HANDLE                  Root;
   1176   EFI_FILE_HANDLE                  ThisFile;
   1177   UINTN                            BufferSize;
   1178   UINT64                           FileSize;
   1179   EFI_FILE_INFO                    *Info;
   1180 
   1181   Root     = NULL;
   1182   ThisFile = NULL;
   1183   //
   1184   // Handle the file system interface to the device
   1185   //
   1186   Status = gBS->HandleProtocol (
   1187                   Device,
   1188                   &gEfiSimpleFileSystemProtocolGuid,
   1189                   (VOID *) &Volume
   1190                   );
   1191   if (EFI_ERROR (Status)) {
   1192     goto Done;
   1193   }
   1194 
   1195   Status = Volume->OpenVolume (
   1196                      Volume,
   1197                      &Root
   1198                      );
   1199   if (EFI_ERROR (Status)) {
   1200     Root = NULL;
   1201     goto Done;
   1202   }
   1203   ASSERT (Root != NULL);
   1204   Status = Root->Open (Root, &ThisFile, FileName, EFI_FILE_MODE_READ, 0);
   1205   if (EFI_ERROR (Status)) {
   1206     goto Done;
   1207   }
   1208   ASSERT (ThisFile != NULL);
   1209 
   1210   //
   1211   // Get file size
   1212   //
   1213   BufferSize  = SIZE_OF_EFI_FILE_INFO + 200;
   1214   do {
   1215     Info   = NULL;
   1216     Status = gBS->AllocatePool (EfiBootServicesData, BufferSize, (VOID **) &Info);
   1217     if (EFI_ERROR (Status)) {
   1218       goto Done;
   1219     }
   1220     Status = ThisFile->GetInfo (
   1221                          ThisFile,
   1222                          &gEfiFileInfoGuid,
   1223                          &BufferSize,
   1224                          Info
   1225                          );
   1226     if (!EFI_ERROR (Status)) {
   1227       break;
   1228     }
   1229     if (Status != EFI_BUFFER_TOO_SMALL) {
   1230       FreePool (Info);
   1231       goto Done;
   1232     }
   1233     FreePool (Info);
   1234   } while (TRUE);
   1235 
   1236   FileSize = Info->FileSize;
   1237   FreePool (Info);
   1238 
   1239   //
   1240   // Read dos header
   1241   //
   1242   BufferSize = sizeof (EFI_IMAGE_DOS_HEADER);
   1243   Status = ThisFile->Read (ThisFile, &BufferSize, DosHeader);
   1244   if (EFI_ERROR (Status) ||
   1245       BufferSize < sizeof (EFI_IMAGE_DOS_HEADER) ||
   1246       FileSize <= DosHeader->e_lfanew ||
   1247       DosHeader->e_magic != EFI_IMAGE_DOS_SIGNATURE) {
   1248     Status = EFI_LOAD_ERROR;
   1249     goto Done;
   1250   }
   1251 
   1252   //
   1253   // Move to PE signature
   1254   //
   1255   Status = ThisFile->SetPosition (ThisFile, DosHeader->e_lfanew);
   1256   if (EFI_ERROR (Status)) {
   1257     Status = EFI_LOAD_ERROR;
   1258     goto Done;
   1259   }
   1260 
   1261   //
   1262   // Read and check PE signature
   1263   //
   1264   BufferSize = sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION);
   1265   Status = ThisFile->Read (ThisFile, &BufferSize, Hdr.Pe32);
   1266   if (EFI_ERROR (Status) ||
   1267       BufferSize < sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION) ||
   1268       Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {
   1269     Status = EFI_LOAD_ERROR;
   1270     goto Done;
   1271   }
   1272 
   1273   //
   1274   // Check PE32 or PE32+ magic
   1275   //
   1276   if (Hdr.Pe32->OptionalHeader.Magic != EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC &&
   1277       Hdr.Pe32->OptionalHeader.Magic != EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
   1278     Status = EFI_LOAD_ERROR;
   1279     goto Done;
   1280   }
   1281 
   1282  Done:
   1283   if (ThisFile != NULL) {
   1284     ThisFile->Close (ThisFile);
   1285   }
   1286   if (Root != NULL) {
   1287     Root->Close (Root);
   1288   }
   1289   return Status;
   1290 }
   1291 
   1292 /**
   1293   This routine adjust the memory information for different memory type and
   1294   save them into the variables for next boot.
   1295 **/
   1296 VOID
   1297 BdsSetMemoryTypeInformationVariable (
   1298   VOID
   1299   )
   1300 {
   1301   EFI_STATUS                   Status;
   1302   EFI_MEMORY_TYPE_INFORMATION  *PreviousMemoryTypeInformation;
   1303   EFI_MEMORY_TYPE_INFORMATION  *CurrentMemoryTypeInformation;
   1304   UINTN                        VariableSize;
   1305   UINTN                        Index;
   1306   UINTN                        Index1;
   1307   UINT32                       Previous;
   1308   UINT32                       Current;
   1309   UINT32                       Next;
   1310   EFI_HOB_GUID_TYPE            *GuidHob;
   1311   BOOLEAN                      MemoryTypeInformationModified;
   1312   BOOLEAN                      MemoryTypeInformationVariableExists;
   1313   EFI_BOOT_MODE                BootMode;
   1314 
   1315   MemoryTypeInformationModified       = FALSE;
   1316   MemoryTypeInformationVariableExists = FALSE;
   1317 
   1318 
   1319   BootMode = GetBootModeHob ();
   1320   //
   1321   // In BOOT_IN_RECOVERY_MODE, Variable region is not reliable.
   1322   //
   1323   if (BootMode == BOOT_IN_RECOVERY_MODE) {
   1324     return;
   1325   }
   1326 
   1327   //
   1328   // Only check the the Memory Type Information variable in the boot mode
   1329   // other than BOOT_WITH_DEFAULT_SETTINGS because the Memory Type
   1330   // Information is not valid in this boot mode.
   1331   //
   1332   if (BootMode != BOOT_WITH_DEFAULT_SETTINGS) {
   1333     VariableSize = 0;
   1334     Status = gRT->GetVariable (
   1335                     EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME,
   1336                     &gEfiMemoryTypeInformationGuid,
   1337                     NULL,
   1338                     &VariableSize,
   1339                     NULL
   1340                     );
   1341     if (Status == EFI_BUFFER_TOO_SMALL) {
   1342       MemoryTypeInformationVariableExists = TRUE;
   1343     }
   1344   }
   1345 
   1346   //
   1347   // Retrieve the current memory usage statistics.  If they are not found, then
   1348   // no adjustments can be made to the Memory Type Information variable.
   1349   //
   1350   Status = EfiGetSystemConfigurationTable (
   1351              &gEfiMemoryTypeInformationGuid,
   1352              (VOID **) &CurrentMemoryTypeInformation
   1353              );
   1354   if (EFI_ERROR (Status) || CurrentMemoryTypeInformation == NULL) {
   1355     return;
   1356   }
   1357 
   1358   //
   1359   // Get the Memory Type Information settings from Hob if they exist,
   1360   // PEI is responsible for getting them from variable and build a Hob to save them.
   1361   // If the previous Memory Type Information is not available, then set defaults
   1362   //
   1363   GuidHob = GetFirstGuidHob (&gEfiMemoryTypeInformationGuid);
   1364   if (GuidHob == NULL) {
   1365     //
   1366     // If Platform has not built Memory Type Info into the Hob, just return.
   1367     //
   1368     return;
   1369   }
   1370   PreviousMemoryTypeInformation = GET_GUID_HOB_DATA (GuidHob);
   1371   VariableSize = GET_GUID_HOB_DATA_SIZE (GuidHob);
   1372 
   1373   //
   1374   // Use a heuristic to adjust the Memory Type Information for the next boot
   1375   //
   1376   DEBUG ((EFI_D_INFO, "Memory  Previous  Current    Next   \n"));
   1377   DEBUG ((EFI_D_INFO, " Type    Pages     Pages     Pages  \n"));
   1378   DEBUG ((EFI_D_INFO, "======  ========  ========  ========\n"));
   1379 
   1380   for (Index = 0; PreviousMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
   1381 
   1382     for (Index1 = 0; CurrentMemoryTypeInformation[Index1].Type != EfiMaxMemoryType; Index1++) {
   1383       if (PreviousMemoryTypeInformation[Index].Type == CurrentMemoryTypeInformation[Index1].Type) {
   1384         break;
   1385       }
   1386     }
   1387     if (CurrentMemoryTypeInformation[Index1].Type == EfiMaxMemoryType) {
   1388       continue;
   1389     }
   1390 
   1391     //
   1392     // Previous is the number of pages pre-allocated
   1393     // Current is the number of pages actually needed
   1394     //
   1395     Previous = PreviousMemoryTypeInformation[Index].NumberOfPages;
   1396     Current  = CurrentMemoryTypeInformation[Index1].NumberOfPages;
   1397     Next     = Previous;
   1398 
   1399     //
   1400     // Inconsistent Memory Reserved across bootings may lead to S4 fail
   1401     // Write next varible to 125% * current when the pre-allocated memory is:
   1402     //  1. More than 150% of needed memory and boot mode is BOOT_WITH_DEFAULT_SETTING
   1403     //  2. Less than the needed memory
   1404     //
   1405     if ((Current + (Current >> 1)) < Previous) {
   1406       if (BootMode == BOOT_WITH_DEFAULT_SETTINGS) {
   1407         Next = Current + (Current >> 2);
   1408       }
   1409     } else if (Current > Previous) {
   1410       Next = Current + (Current >> 2);
   1411     }
   1412     if (Next > 0 && Next < 4) {
   1413       Next = 4;
   1414     }
   1415 
   1416     if (Next != Previous) {
   1417       PreviousMemoryTypeInformation[Index].NumberOfPages = Next;
   1418       MemoryTypeInformationModified = TRUE;
   1419     }
   1420 
   1421     DEBUG ((EFI_D_INFO, "  %02x    %08x  %08x  %08x\n", PreviousMemoryTypeInformation[Index].Type, Previous, Current, Next));
   1422   }
   1423 
   1424   //
   1425   // If any changes were made to the Memory Type Information settings, then set the new variable value;
   1426   // Or create the variable in first boot.
   1427   //
   1428   if (MemoryTypeInformationModified || !MemoryTypeInformationVariableExists) {
   1429     Status = SetVariableAndReportStatusCodeOnError (
   1430                EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME,
   1431                &gEfiMemoryTypeInformationGuid,
   1432                EFI_VARIABLE_NON_VOLATILE  | EFI_VARIABLE_BOOTSERVICE_ACCESS,
   1433                VariableSize,
   1434                PreviousMemoryTypeInformation
   1435                );
   1436 
   1437     if (!EFI_ERROR (Status)) {
   1438       //
   1439       // If the Memory Type Information settings have been modified, then reset the platform
   1440       // so the new Memory Type Information setting will be used to guarantee that an S4
   1441       // entry/resume cycle will not fail.
   1442       //
   1443       if (MemoryTypeInformationModified && PcdGetBool (PcdResetOnMemoryTypeInformationChange)) {
   1444         DEBUG ((EFI_D_INFO, "Memory Type Information settings change. Warm Reset!!!\n"));
   1445         gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);
   1446       }
   1447     } else {
   1448       DEBUG ((EFI_D_ERROR, "Memory Type Information settings cannot be saved. OS S4 may fail!\n"));
   1449     }
   1450   }
   1451 }
   1452 
   1453 /**
   1454   This routine is kept for backward compatibility.
   1455 **/
   1456 VOID
   1457 EFIAPI
   1458 BdsLibSaveMemoryTypeInformation (
   1459   VOID
   1460   )
   1461 {
   1462 }
   1463 
   1464 
   1465 /**
   1466   Identify a user and, if authenticated, returns the current user profile handle.
   1467 
   1468   @param[out]  User           Point to user profile handle.
   1469 
   1470   @retval EFI_SUCCESS         User is successfully identified, or user identification
   1471                               is not supported.
   1472   @retval EFI_ACCESS_DENIED   User is not successfully identified
   1473 
   1474 **/
   1475 EFI_STATUS
   1476 EFIAPI
   1477 BdsLibUserIdentify (
   1478   OUT EFI_USER_PROFILE_HANDLE         *User
   1479   )
   1480 {
   1481   EFI_STATUS                          Status;
   1482   EFI_USER_MANAGER_PROTOCOL           *Manager;
   1483 
   1484   Status = gBS->LocateProtocol (
   1485                   &gEfiUserManagerProtocolGuid,
   1486                   NULL,
   1487                   (VOID **) &Manager
   1488                   );
   1489   if (EFI_ERROR (Status)) {
   1490     return EFI_SUCCESS;
   1491   }
   1492 
   1493   return Manager->Identify (Manager, User);
   1494 }
   1495 
   1496 /**
   1497   Set the variable and report the error through status code upon failure.
   1498 
   1499   @param  VariableName           A Null-terminated string that is the name of the vendor's variable.
   1500                                  Each VariableName is unique for each VendorGuid. VariableName must
   1501                                  contain 1 or more characters. If VariableName is an empty string,
   1502                                  then EFI_INVALID_PARAMETER is returned.
   1503   @param  VendorGuid             A unique identifier for the vendor.
   1504   @param  Attributes             Attributes bitmask to set for the variable.
   1505   @param  DataSize               The size in bytes of the Data buffer. Unless the EFI_VARIABLE_APPEND_WRITE,
   1506                                  EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, or
   1507                                  EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute is set, a size of zero
   1508                                  causes the variable to be deleted. When the EFI_VARIABLE_APPEND_WRITE attribute is
   1509                                  set, then a SetVariable() call with a DataSize of zero will not cause any change to
   1510                                  the variable value (the timestamp associated with the variable may be updated however
   1511                                  even if no new data value is provided,see the description of the
   1512                                  EFI_VARIABLE_AUTHENTICATION_2 descriptor below. In this case the DataSize will not
   1513                                  be zero since the EFI_VARIABLE_AUTHENTICATION_2 descriptor will be populated).
   1514   @param  Data                   The contents for the variable.
   1515 
   1516   @retval EFI_SUCCESS            The firmware has successfully stored the variable and its data as
   1517                                  defined by the Attributes.
   1518   @retval EFI_INVALID_PARAMETER  An invalid combination of attribute bits, name, and GUID was supplied, or the
   1519                                  DataSize exceeds the maximum allowed.
   1520   @retval EFI_INVALID_PARAMETER  VariableName is an empty string.
   1521   @retval EFI_OUT_OF_RESOURCES   Not enough storage is available to hold the variable and its data.
   1522   @retval EFI_DEVICE_ERROR       The variable could not be retrieved due to a hardware error.
   1523   @retval EFI_WRITE_PROTECTED    The variable in question is read-only.
   1524   @retval EFI_WRITE_PROTECTED    The variable in question cannot be deleted.
   1525   @retval EFI_SECURITY_VIOLATION The variable could not be written due to EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
   1526                                  or EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACESS being set, but the AuthInfo
   1527                                  does NOT pass the validation check carried out by the firmware.
   1528 
   1529   @retval EFI_NOT_FOUND          The variable trying to be updated or deleted was not found.
   1530 **/
   1531 EFI_STATUS
   1532 SetVariableAndReportStatusCodeOnError (
   1533   IN CHAR16     *VariableName,
   1534   IN EFI_GUID   *VendorGuid,
   1535   IN UINT32     Attributes,
   1536   IN UINTN      DataSize,
   1537   IN VOID       *Data
   1538   )
   1539 {
   1540   EFI_STATUS                 Status;
   1541   EDKII_SET_VARIABLE_STATUS  *SetVariableStatus;
   1542   UINTN                      NameSize;
   1543 
   1544   Status = gRT->SetVariable (
   1545                   VariableName,
   1546                   VendorGuid,
   1547                   Attributes,
   1548                   DataSize,
   1549                   Data
   1550                   );
   1551   if (EFI_ERROR (Status)) {
   1552     NameSize = StrSize (VariableName);
   1553     SetVariableStatus = AllocatePool (sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + DataSize);
   1554     if (SetVariableStatus != NULL) {
   1555       CopyGuid (&SetVariableStatus->Guid, VendorGuid);
   1556       SetVariableStatus->NameSize   = NameSize;
   1557       SetVariableStatus->DataSize   = DataSize;
   1558       SetVariableStatus->SetStatus  = Status;
   1559       SetVariableStatus->Attributes = Attributes;
   1560       CopyMem (SetVariableStatus + 1,                          VariableName, NameSize);
   1561       if ((Data != NULL) && (DataSize != 0)) {
   1562         CopyMem (((UINT8 *) (SetVariableStatus + 1)) + NameSize, Data,         DataSize);
   1563       }
   1564 
   1565       REPORT_STATUS_CODE_EX (
   1566         EFI_ERROR_CODE,
   1567         PcdGet32 (PcdErrorCodeSetVariable),
   1568         0,
   1569         NULL,
   1570         &gEdkiiStatusCodeDataTypeVariableGuid,
   1571         SetVariableStatus,
   1572         sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + DataSize
   1573         );
   1574 
   1575       FreePool (SetVariableStatus);
   1576     }
   1577   }
   1578 
   1579   return Status;
   1580 }
   1581 
   1582