]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Library/UefiBootManagerLib/BmLoadOption.c
MdeModulePkg/UefiBootManagerLib: Refine the debug message
[mirror_edk2.git] / MdeModulePkg / Library / UefiBootManagerLib / BmLoadOption.c
index 630307ed031778dacd78897df4f98e358609672f..6f705bd4673f12a74919248cc5a229ace880e4d5 100644 (file)
@@ -1,7 +1,8 @@
 /** @file\r
   Load option library functions which relate with creating and processing load options.\r
 \r
-Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.<BR>\r
+(C) Copyright 2015-2016 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
@@ -18,14 +19,16 @@ GLOBAL_REMOVE_IF_UNREFERENCED
   CHAR16 *mBmLoadOptionName[] = {\r
     L"Driver",\r
     L"SysPrep",\r
-    L"Boot"\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
+    EFI_BOOT_ORDER_VARIABLE_NAME,\r
+    NULL  // PlatformRecovery#### doesn't have associated *Order variable\r
   };\r
 \r
 /**\r
@@ -36,7 +39,7 @@ GLOBAL_REMOVE_IF_UNREFERENCED
 **/\r
 VOID\r
 BmForEachVariable (\r
-  VARIABLE_VISITOR            Visitor,\r
+  BM_VARIABLE_VISITOR         Visitor,\r
   VOID                        *Context\r
   )\r
 {\r
@@ -100,6 +103,8 @@ BmGetFreeOptionNumber (
           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
@@ -151,8 +156,9 @@ BmGetFreeOptionNumber (
 }\r
 \r
 /**\r
-  Create the Boot####, Driver####, SysPrep####, variable from the load option.\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
@@ -164,12 +170,14 @@ EfiBootManagerLoadOptionToVariable (
   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
@@ -230,6 +238,17 @@ structure.
   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
   return gRT->SetVariable (\r
                 OptionName,\r
@@ -268,6 +287,7 @@ BmAddOptionNumberToOrderVariable (
   // 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
@@ -501,7 +521,8 @@ EfiBootManagerInitializeLoadOption (
   @retval 0 ~ Count-1 The index of the Key in the Array.\r
 **/\r
 INTN\r
-BmFindLoadOption (\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
@@ -543,31 +564,32 @@ EfiBootManagerDeleteLoadOptionVariable (
 {\r
   UINT16                            *OptionOrder;\r
   UINTN                             OptionOrderSize;\r
-  EFI_STATUS                        Status;\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
-  Status = EFI_NOT_FOUND;\r
-\r
   if (OptionType == LoadOptionTypeDriver || OptionType == LoadOptionTypeSysPrep || OptionType == LoadOptionTypeBoot) {\r
     //\r
-    // If the associated *Order exists, just remove the reference in *Order.\r
+    // If the associated *Order exists, firstly remove the reference in *Order for\r
+    //  Driver####, SysPrep#### and Boot####.\r
     //\r
-    GetEfiGlobalVariable2 (mBmLoadOptionOrderName[OptionType], &OptionOrder, &OptionOrderSize);\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
-        Status = 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
+        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
@@ -576,30 +598,17 @@ EfiBootManagerDeleteLoadOptionVariable (
     }\r
   }\r
 \r
-  return Status;\r
-}\r
-\r
-/**\r
-  Convert a single character to number.\r
-  It assumes the input Char is in the scope of L'0' ~ L'9' and L'A' ~ L'F'\r
-\r
-  @param    Char   The input char which need to convert to int.\r
-**/\r
-UINTN\r
-BmCharToUint (\r
-  IN CHAR16                           Char\r
-  )\r
-{\r
-  if ((Char >= L'0') && (Char <= L'9')) {\r
-    return (UINTN) (Char - L'0');\r
-  }\r
-\r
-  if ((Char >= L'A') && (Char <= L'F')) {\r
-    return (UINTN) (Char - L'A' + 0xA);\r
-  }\r
-\r
-  ASSERT (FALSE);\r
-  return (UINTN) -1;\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
@@ -693,7 +702,8 @@ BmStrSizeEx (
 }\r
 \r
 /**\r
-  Validate the Boot####, Driver####, SysPrep#### variable (VendorGuid/Name)\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
@@ -765,23 +775,28 @@ BmValidateOption (
   @retval FALSE The variable name is NOT valid.\r
 **/\r
 BOOLEAN\r
-BmIsValidLoadOptionVariableName (\r
+EFIAPI\r
+EfiBootManagerIsValidLoadOptionVariableName (\r
   IN CHAR16                             *VariableName,\r
-  OUT EFI_BOOT_MANAGER_LOAD_OPTION_TYPE *OptionType,\r
-  OUT UINT16                            *OptionNumber\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
 \r
+  if (VariableName == NULL) {\r
+    return FALSE;\r
+  }\r
+\r
   VariableNameLen = StrLen (VariableName);\r
 \r
   if (VariableNameLen <= 4) {\r
     return FALSE;\r
   }\r
 \r
-  for (Index = 0; Index < sizeof (mBmLoadOptionName) / sizeof (mBmLoadOptionName[0]); Index++) {\r
+  for (Index = 0; Index < ARRAY_SIZE (mBmLoadOptionName); Index++) {\r
     if ((VariableNameLen - 4 == StrLen (mBmLoadOptionName[Index])) &&\r
         (StrnCmp (VariableName, mBmLoadOptionName[Index], VariableNameLen - 4) == 0)\r
         ) {\r
@@ -789,18 +804,23 @@ BmIsValidLoadOptionVariableName (
     }\r
   }\r
 \r
-  if (Index == sizeof (mBmLoadOptionName) / sizeof (mBmLoadOptionName[0])) {\r
+  if (Index == ARRAY_SIZE (mBmLoadOptionName)) {\r
     return FALSE;\r
   }\r
 \r
-  *OptionType = (EFI_BOOT_MANAGER_LOAD_OPTION_TYPE) Index;\r
-  *OptionNumber = 0;\r
-  for (Index = VariableNameLen - 4; Index < VariableNameLen; Index++) {\r
-    Uint = BmCharToUint (VariableName[Index]);\r
-    if (Uint == -1) {\r
-      break;\r
-    } else {\r
-      *OptionNumber = (UINT16) Uint + *OptionNumber * 0x10;\r
+  if (OptionType != NULL) {\r
+    *OptionType = (EFI_BOOT_MANAGER_LOAD_OPTION_TYPE) Index;\r
+  }\r
+\r
+  if (OptionNumber != NULL) {\r
+    *OptionNumber = 0;\r
+    for (Index = VariableNameLen - 4; Index < VariableNameLen; Index++) {\r
+      Uint = BmCharToUint (VariableName[Index]);\r
+      if (Uint == -1) {\r
+        break;\r
+      } else {\r
+        *OptionNumber = (UINT16) Uint + *OptionNumber * 0x10;\r
+      }\r
     }\r
   }\r
 \r
@@ -843,7 +863,7 @@ EfiBootManagerVariableToLoadOptionEx (
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
-  if (!BmIsValidLoadOptionVariableName (VariableName, &OptionType, &OptionNumber)) {\r
+  if (!EfiBootManagerIsValidLoadOptionVariableName (VariableName, &OptionType, &OptionNumber)) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
@@ -936,6 +956,62 @@ EfiBootManagerVariableToLoadOption (
   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
@@ -955,16 +1031,18 @@ EfiBootManagerGetLoadOptions (
   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
+  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
@@ -1005,8 +1083,16 @@ EfiBootManagerGetLoadOptions (
       *OptionCount = OptionIndex;\r
     }\r
 \r
-  } else {\r
-    return NULL;\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
@@ -1134,7 +1220,8 @@ BmIsLoadOptionPeHeaderValid (
         if ((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 == LoadOptionTypeBoot && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) ||\r
+            (Type == LoadOptionTypePlatformRecovery && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION)\r
             ) {\r
           return TRUE;\r
         }\r
@@ -1190,11 +1277,12 @@ EfiBootManagerProcessLoadOption (
   // Load and start the load option.\r
   //\r
   DEBUG ((\r
-    DEBUG_INFO | DEBUG_LOAD, "Process Load Option (%s%04x) ...\n",\r
-    mBmLoadOptionName[LoadOption->OptionType], LoadOption->OptionNumber\r
+    DEBUG_INFO | DEBUG_LOAD, "Process %s%04x (%s) ...\n",\r
+    mBmLoadOptionName[LoadOption->OptionType], LoadOption->OptionNumber,\r
+    LoadOption->Description\r
     ));\r
   ImageHandle = NULL;\r
-  FileBuffer = BmGetLoadOptionBuffer (LoadOption->FilePath, &FilePath, &FileSize);\r
+  FileBuffer = EfiBootManagerGetLoadOptionBuffer (LoadOption->FilePath, &FilePath, &FileSize);\r
   DEBUG_CODE (\r
     if (FileBuffer != NULL && CompareMem (LoadOption->FilePath, FilePath, GetDevicePathSize (FilePath)) != 0) {\r
       DEBUG ((EFI_D_INFO, "[Bds] DevicePath expand: "));\r
@@ -1234,7 +1322,7 @@ EfiBootManagerProcessLoadOption (
 \r
     LoadOption->Status = gBS->StartImage (ImageHandle, &LoadOption->ExitDataSize, &LoadOption->ExitData);\r
     DEBUG ((\r
-      DEBUG_INFO | DEBUG_LOAD, "Load Option (%s%04x) Return Status = %r\n",\r
+      DEBUG_INFO | DEBUG_LOAD, "%s%04x Return Status = %r\n",\r
       mBmLoadOptionName[LoadOption->OptionType], LoadOption->OptionNumber, LoadOption->Status\r
       ));\r
 \r