]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleService.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Universal / CapsuleRuntimeDxe / CapsuleService.c
index a3b53262ef3a29f702f724ac75f698813d9082c3..50968a839e84a1ba2109fd80f254e2c828255c67 100644 (file)
@@ -1,34 +1,15 @@
 /** @file\r
   Capsule Runtime Driver produces two UEFI capsule runtime services.\r
   (UpdateCapsule, QueryCapsuleCapabilities)\r
-  It installs the Capsule Architectural Protocol defined in PI1.0a to signify \r
+  It installs the Capsule Architectural Protocol defined in PI1.0a to signify\r
   the capsule runtime services are ready.\r
 \r
-Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
-This program and the accompanying materials\r
-are licensed and made available under the terms and conditions of the BSD License\r
-which accompanies this distribution.  The full text of the license may be found at\r
-http://opensource.org/licenses/bsd-license.php\r
-\r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+Copyright (c) 2006 - 2020, Intel Corporation. All rights reserved.<BR>\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
-#include <Uefi.h>\r
-\r
-#include <Protocol/Capsule.h>\r
-#include <Guid/CapsuleVendor.h>\r
-\r
-#include <Library/DebugLib.h>\r
-#include <Library/PcdLib.h>\r
-#include <Library/CapsuleLib.h>\r
-#include <Library/UefiDriverEntryPoint.h>\r
-#include <Library/UefiBootServicesTableLib.h>\r
-#include <Library/UefiRuntimeServicesTableLib.h>\r
-#include <Library/UefiRuntimeLib.h>\r
-#include <Library/BaseLib.h>\r
-#include <Library/PrintLib.h>\r
+#include "CapsuleService.h"\r
 \r
 //\r
 // Handle for the installation of Capsule Architecture Protocol.\r
@@ -38,7 +19,10 @@ EFI_HANDLE  mNewHandle = NULL;
 //\r
 // The times of calling UpdateCapsule ()\r
 //\r
-UINTN       mTimes      = 0;\r
+UINTN  mTimes = 0;\r
+\r
+UINT32  mMaxSizePopulateCapsule    = 0;\r
+UINT32  mMaxSizeNonPopulateCapsule = 0;\r
 \r
 /**\r
   Passes capsules to the firmware with both virtual and physical mapping. Depending on the intended\r
@@ -64,24 +48,37 @@ UINTN       mTimes      = 0;
   @retval EFI_INVALID_PARAMETER CapsuleCount is Zero.\r
   @retval EFI_INVALID_PARAMETER For across reset capsule image, ScatterGatherList is NULL.\r
   @retval EFI_UNSUPPORTED       CapsuleImage is not recognized by the firmware.\r
+  @retval EFI_OUT_OF_RESOURCES  When ExitBootServices() has been previously called this error indicates the capsule\r
+                                is compatible with this platform but is not capable of being submitted or processed\r
+                                in runtime. The caller may resubmit the capsule prior to ExitBootServices().\r
+  @retval EFI_OUT_OF_RESOURCES  When ExitBootServices() has not been previously called then this error indicates\r
+                                the capsule is compatible with this platform but there are insufficient resources to process.\r
 \r
 **/\r
 EFI_STATUS\r
 EFIAPI\r
 UpdateCapsule (\r
-  IN EFI_CAPSULE_HEADER      **CapsuleHeaderArray,\r
-  IN UINTN                   CapsuleCount,\r
-  IN EFI_PHYSICAL_ADDRESS    ScatterGatherList OPTIONAL\r
+  IN EFI_CAPSULE_HEADER    **CapsuleHeaderArray,\r
+  IN UINTN                 CapsuleCount,\r
+  IN EFI_PHYSICAL_ADDRESS  ScatterGatherList OPTIONAL\r
   )\r
 {\r
-  UINTN                     ArrayNumber;\r
-  EFI_STATUS                Status;\r
-  EFI_CAPSULE_HEADER        *CapsuleHeader;\r
-  BOOLEAN                   NeedReset;\r
-  BOOLEAN                   InitiateReset;\r
-  CHAR16                    CapsuleVarName[30];\r
-  CHAR16                    *TempVarName;  \r
-  \r
+  UINTN               ArrayNumber;\r
+  EFI_STATUS          Status;\r
+  EFI_CAPSULE_HEADER  *CapsuleHeader;\r
+  BOOLEAN             NeedReset;\r
+  BOOLEAN             InitiateReset;\r
+  CHAR16              CapsuleVarName[30];\r
+  CHAR16              *TempVarName;\r
+\r
+  //\r
+  // Check if platform support Capsule In RAM or not.\r
+  // Platform could choose to drop CapsulePei/CapsuleX64 and do not support Capsule In RAM.\r
+  //\r
+  if (!PcdGetBool (PcdCapsuleInRamSupport)) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
   //\r
   // Capsule Count can't be less than one.\r
   //\r
@@ -103,6 +100,7 @@ UpdateCapsule (
     if ((CapsuleHeader->Flags & (CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE)) == CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) {\r
       return EFI_INVALID_PARAMETER;\r
     }\r
+\r
     //\r
     // A capsule which has the CAPSULE_FLAGS_INITIATE_RESET flag must have\r
     // CAPSULE_FLAGS_PERSIST_ACROSS_RESET set in its header as well.\r
@@ -110,12 +108,24 @@ UpdateCapsule (
     if ((CapsuleHeader->Flags & (CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_INITIATE_RESET)) == CAPSULE_FLAGS_INITIATE_RESET) {\r
       return EFI_INVALID_PARAMETER;\r
     }\r
+\r
     //\r
-    // Check Capsule image without populate flag by firmware support capsule function  \r
+    // Check FMP capsule flag\r
     //\r
-    if (((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) == 0) && \r
-        (SupportCapsuleImage (CapsuleHeader) != EFI_SUCCESS)) {\r
-      return EFI_UNSUPPORTED;\r
+    if (  CompareGuid (&CapsuleHeader->CapsuleGuid, &gEfiFmpCapsuleGuid)\r
+       && ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) != 0))\r
+    {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    //\r
+    // Check Capsule image without populate flag by firmware support capsule function\r
+    //\r
+    if ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) == 0) {\r
+      Status = SupportCapsuleImage (CapsuleHeader);\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
     }\r
   }\r
 \r
@@ -123,19 +133,20 @@ UpdateCapsule (
   // Walk through all capsules, record whether there is a capsule needs reset\r
   // or initiate reset. And then process capsules which has no reset flag directly.\r
   //\r
-  for (ArrayNumber = 0; ArrayNumber < CapsuleCount ; ArrayNumber++) {\r
+  for (ArrayNumber = 0; ArrayNumber < CapsuleCount; ArrayNumber++) {\r
     CapsuleHeader = CapsuleHeaderArray[ArrayNumber];\r
     //\r
     // Here should be in the boot-time for non-reset capsule image\r
     // Platform specific update for the non-reset capsule image.\r
     //\r
     if ((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) == 0) {\r
-      if (EfiAtRuntime ()) { \r
-        Status = EFI_UNSUPPORTED;\r
+      if (EfiAtRuntime () && !FeaturePcdGet (PcdSupportProcessCapsuleAtRuntime)) {\r
+        Status = EFI_OUT_OF_RESOURCES;\r
       } else {\r
-        Status = ProcessCapsuleImage(CapsuleHeader);\r
+        Status = ProcessCapsuleImage (CapsuleHeader);\r
       }\r
-      if (EFI_ERROR(Status)) {\r
+\r
+      if (EFI_ERROR (Status)) {\r
         return Status;\r
       }\r
     } else {\r
@@ -145,7 +156,7 @@ UpdateCapsule (
       }\r
     }\r
   }\r
-  \r
+\r
   //\r
   // After launching all capsules who has no reset flag, if no more capsules claims\r
   // for a system reset just return.\r
@@ -156,32 +167,40 @@ UpdateCapsule (
 \r
   //\r
   // ScatterGatherList is only referenced if the capsules are defined to persist across\r
-  // system reset. \r
+  // system reset.\r
   //\r
-  if (ScatterGatherList == (EFI_PHYSICAL_ADDRESS) (UINTN) NULL) {\r
+  if (ScatterGatherList == (EFI_PHYSICAL_ADDRESS)(UINTN)NULL) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
   //\r
   // Check if the platform supports update capsule across a system reset\r
   //\r
-  if (!FeaturePcdGet(PcdSupportUpdateCapsuleReset)) {\r
+  if (!IsPersistAcrossResetCapsuleSupported ()) {\r
     return EFI_UNSUPPORTED;\r
   }\r
 \r
+  CapsuleCacheWriteBack (ScatterGatherList);\r
+\r
   //\r
   // Construct variable name CapsuleUpdateData, CapsuleUpdateData1, CapsuleUpdateData2...\r
   // if user calls UpdateCapsule multiple times.\r
   //\r
-  StrCpy (CapsuleVarName, EFI_CAPSULE_VARIABLE_NAME);\r
+  StrCpyS (CapsuleVarName, sizeof (CapsuleVarName)/sizeof (CHAR16), EFI_CAPSULE_VARIABLE_NAME);\r
   TempVarName = CapsuleVarName + StrLen (CapsuleVarName);\r
   if (mTimes > 0) {\r
-    UnicodeValueToString (TempVarName, 0, mTimes, 0);\r
+    UnicodeValueToStringS (\r
+      TempVarName,\r
+      sizeof (CapsuleVarName) - ((UINTN)TempVarName - (UINTN)CapsuleVarName),\r
+      0,\r
+      mTimes,\r
+      0\r
+      );\r
   }\r
 \r
   //\r
   // ScatterGatherList is only referenced if the capsules are defined to persist across\r
-  // system reset. Set its value into NV storage to let pre-boot driver to pick it up \r
+  // system reset. Set its value into NV storage to let pre-boot driver to pick it up\r
   // after coming through a system reset.\r
   //\r
   Status = EfiSetVariable (\r
@@ -189,27 +208,30 @@ UpdateCapsule (
              &gEfiCapsuleVendorGuid,\r
              EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
              sizeof (UINTN),\r
-             (VOID *) &ScatterGatherList\r
+             (VOID *)&ScatterGatherList\r
              );\r
   if (!EFI_ERROR (Status)) {\r
-     //\r
-     // Variable has been set successfully, increase variable index.\r
-     //\r
-     mTimes++;\r
-     if(InitiateReset) {\r
-       //\r
-       // Firmware that encounters a capsule which has the CAPSULE_FLAGS_INITIATE_RESET Flag set in its header\r
-       // will initiate a reset of the platform which is compatible with the passed-in capsule request and will \r
-       // not return back to the caller.\r
-       //\r
-       EfiResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);\r
-     }\r
+    //\r
+    // Variable has been set successfully, increase variable index.\r
+    //\r
+    mTimes++;\r
+    if (InitiateReset) {\r
+      //\r
+      // Firmware that encounters a capsule which has the CAPSULE_FLAGS_INITIATE_RESET Flag set in its header\r
+      // will initiate a reset of the platform which is compatible with the passed-in capsule request and will\r
+      // not return back to the caller.\r
+      //\r
+      EfiResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);\r
+    }\r
   }\r
+\r
   return Status;\r
 }\r
 \r
 /**\r
   Returns if the capsule can be supported via UpdateCapsule().\r
+  Notice: When PcdCapsuleInRamSupport is unsupported, even this routine returns a valid answer,\r
+  the capsule still is unsupported via UpdateCapsule().\r
 \r
   @param  CapsuleHeaderArray    Virtual pointer to an array of virtual pointers to the capsules\r
                                 being passed into update capsule.\r
@@ -230,14 +252,16 @@ UpdateCapsule (
 EFI_STATUS\r
 EFIAPI\r
 QueryCapsuleCapabilities (\r
-  IN  EFI_CAPSULE_HEADER   **CapsuleHeaderArray,\r
-  IN  UINTN                CapsuleCount,\r
-  OUT UINT64               *MaxiumCapsuleSize,\r
-  OUT EFI_RESET_TYPE       *ResetType\r
+  IN  EFI_CAPSULE_HEADER  **CapsuleHeaderArray,\r
+  IN  UINTN               CapsuleCount,\r
+  OUT UINT64              *MaxiumCapsuleSize,\r
+  OUT EFI_RESET_TYPE      *ResetType\r
   )\r
 {\r
-  UINTN                     ArrayNumber;\r
-  EFI_CAPSULE_HEADER        *CapsuleHeader;\r
+  EFI_STATUS          Status;\r
+  UINTN               ArrayNumber;\r
+  EFI_CAPSULE_HEADER  *CapsuleHeader;\r
+  BOOLEAN             NeedReset;\r
 \r
   //\r
   // Capsule Count can't be less than one.\r
@@ -245,15 +269,16 @@ QueryCapsuleCapabilities (
   if (CapsuleCount < 1) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
-  \r
+\r
   //\r
   // Check whether input parameter is valid\r
   //\r
-  if ((MaxiumCapsuleSize == NULL) ||(ResetType == NULL)) {\r
+  if ((MaxiumCapsuleSize == NULL) || (ResetType == NULL)) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
   CapsuleHeader = NULL;\r
+  NeedReset     = FALSE;\r
 \r
   for (ArrayNumber = 0; ArrayNumber < CapsuleCount; ArrayNumber++) {\r
     CapsuleHeader = CapsuleHeaderArray[ArrayNumber];\r
@@ -264,6 +289,7 @@ QueryCapsuleCapabilities (
     if ((CapsuleHeader->Flags & (CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE)) == CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) {\r
       return EFI_INVALID_PARAMETER;\r
     }\r
+\r
     //\r
     // A capsule which has the CAPSULE_FLAGS_INITIATE_RESET flag must have\r
     // CAPSULE_FLAGS_PERSIST_ACROSS_RESET set in its header as well.\r
@@ -271,71 +297,95 @@ QueryCapsuleCapabilities (
     if ((CapsuleHeader->Flags & (CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_INITIATE_RESET)) == CAPSULE_FLAGS_INITIATE_RESET) {\r
       return EFI_INVALID_PARAMETER;\r
     }\r
+\r
+    //\r
+    // Check FMP capsule flag\r
+    //\r
+    if (  CompareGuid (&CapsuleHeader->CapsuleGuid, &gEfiFmpCapsuleGuid)\r
+       && ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) != 0))\r
+    {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
     //\r
     // Check Capsule image without populate flag is supported by firmware\r
     //\r
-    if (((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) == 0) && \r
-        (SupportCapsuleImage (CapsuleHeader) != EFI_SUCCESS)) {\r
-      return EFI_UNSUPPORTED;\r
+    if ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) == 0) {\r
+      Status = SupportCapsuleImage (CapsuleHeader);\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
     }\r
   }\r
 \r
   //\r
-  // Assume that capsules have the same flags on reseting or not.\r
+  // Find out whether there is any capsule defined to persist across system reset.\r
   //\r
-  CapsuleHeader = CapsuleHeaderArray[0];\r
-  if ((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) {\r
+  for (ArrayNumber = 0; ArrayNumber < CapsuleCount; ArrayNumber++) {\r
+    CapsuleHeader = CapsuleHeaderArray[ArrayNumber];\r
+    if ((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) {\r
+      NeedReset = TRUE;\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (NeedReset) {\r
     //\r
-    //Check if the platform supports update capsule across a system reset\r
+    // Check if the platform supports update capsule across a system reset\r
     //\r
-    if (!FeaturePcdGet(PcdSupportUpdateCapsuleReset)) {\r
+    if (!IsPersistAcrossResetCapsuleSupported ()) {\r
       return EFI_UNSUPPORTED;\r
     }\r
-    *ResetType = EfiResetWarm;   \r
+\r
+    *ResetType         = EfiResetWarm;\r
+    *MaxiumCapsuleSize = (UINT64)mMaxSizePopulateCapsule;\r
   } else {\r
     //\r
     // For non-reset capsule image.\r
     //\r
-    *ResetType = EfiResetCold;\r
-  }\r
-  \r
-  //\r
-  // The support max capsule image size\r
-  //\r
-  if ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) != 0) {\r
-    *MaxiumCapsuleSize = PcdGet32(PcdMaxSizePopulateCapsule);\r
-  } else {\r
-    *MaxiumCapsuleSize = PcdGet32(PcdMaxSizeNonPopulateCapsule);\r
+    *ResetType         = EfiResetCold;\r
+    *MaxiumCapsuleSize = (UINT64)mMaxSizeNonPopulateCapsule;\r
   }\r
 \r
   return EFI_SUCCESS;\r
 }\r
 \r
-\r
 /**\r
 \r
   This code installs UEFI capsule runtime service.\r
 \r
-  @param  ImageHandle    The firmware allocated handle for the EFI image.  \r
+  @param  ImageHandle    The firmware allocated handle for the EFI image.\r
   @param  SystemTable    A pointer to the EFI System Table.\r
 \r
-  @retval EFI_SUCCESS    UEFI Capsule Runtime Services are installed successfully. \r
+  @retval EFI_SUCCESS    UEFI Capsule Runtime Services are installed successfully.\r
 \r
 **/\r
 EFI_STATUS\r
 EFIAPI\r
 CapsuleServiceInitialize (\r
-  IN EFI_HANDLE         ImageHandle,\r
-  IN EFI_SYSTEM_TABLE   *SystemTable\r
+  IN EFI_HANDLE        ImageHandle,\r
+  IN EFI_SYSTEM_TABLE  *SystemTable\r
   )\r
 {\r
   EFI_STATUS  Status;\r
-  \r
+\r
+  mMaxSizePopulateCapsule    = PcdGet32 (PcdMaxSizePopulateCapsule);\r
+  mMaxSizeNonPopulateCapsule = PcdGet32 (PcdMaxSizeNonPopulateCapsule);\r
+\r
+  //\r
+  // When PEI phase is IA32, DXE phase is X64, it is possible that capsule data are\r
+  // put above 4GB, so capsule PEI will transfer to long mode to get capsule data.\r
+  // The page table and stack is used to transfer processor mode from IA32 to long mode.\r
+  // Create the base address of page table and stack, and save them into variable.\r
+  // This is not needed when capsule with reset type is not supported.\r
+  //\r
+  SaveLongModeContext ();\r
+\r
   //\r
   // Install capsule runtime services into UEFI runtime service tables.\r
   //\r
-  gRT->UpdateCapsule                    = UpdateCapsule;\r
-  gRT->QueryCapsuleCapabilities         = QueryCapsuleCapabilities;\r
+  gRT->UpdateCapsule            = UpdateCapsule;\r
+  gRT->QueryCapsuleCapabilities = QueryCapsuleCapabilities;\r
 \r
   //\r
   // Install the Capsule Architectural Protocol on a new handle\r