From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: mx.groups.io; dkim=missing; spf=pass (domain: intel.com, ip: 134.134.136.24, mailfrom: zhichao.gao@intel.com) Received: from mga09.intel.com (mga09.intel.com [134.134.136.24]) by groups.io with SMTP; Thu, 30 May 2019 18:48:10 -0700 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga007.jf.intel.com ([10.7.209.58]) by orsmga102.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 30 May 2019 18:48:09 -0700 X-ExtLoop1: 1 Received: from fieedk001.ccr.corp.intel.com ([10.239.33.119]) by orsmga007.jf.intel.com with ESMTP; 30 May 2019 18:48:06 -0700 From: "Gao, Zhichao" To: devel@edk2.groups.io Cc: Bret Barkelew , Jian J Wang , Hao A Wu , Ray Ni , Star Zeng , Liming Gao , Sean Brogan , Michael Turner , Zhichao gao Subject: [PATCH V2] MdeModulePkg/CapsulePei: Optimize the CapsulePei Date: Fri, 31 May 2019 09:48:05 +0800 Message-Id: <20190531014805.9676-1-zhichao.gao@intel.com> X-Mailer: git-send-email 2.21.0.windows.1 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit From: Bret Barkelew REF: https://bugzilla.tianocore.org/show_bug.cgi?id=1853 Optimize some function in CapsulePei to make it easier to maintian. 1. Separate the capsule check function form GetCapsuleDescriptors to AreCapsulesStaged. The original logic is unclear. 2. Avoid querying the capsule variable twice. First time to count the number of SG list and allocate a buffer to save SG list data. Second time to save the SG list data to the buffer. Modified: Using a template buffer to save the SG list data. After query, we get the number of SG list, then allocate memory and copy data form template buffer to the allocated memory. 3. Using MemoryAllocationLib instead of memory function in Pei services. 4, Remain 2 byte(CHAR16) to be the null-terminate of CapsuleVarName. Cc: Jian J Wang Cc: Hao A Wu Cc: Ray Ni Cc: Star Zeng Cc: Liming Gao Cc: Sean Brogan Cc: Michael Turner Cc: Bret Barkelew Signed-off-by: Zhichao gao --- Code change from https://github.com/microsoft/mu_basecore/blob/release/201903/MdeModulePkg/Universal/CapsulePei/UefiCapsule.c#L801 Note: 1. Change the AreCapsulesStaged: directly return the BOOLEAN result. 2. While the template buffer is to small, double its size through memory function. MdeModulePkg/Universal/CapsulePei/Capsule.h | 3 +- .../Universal/CapsulePei/CapsulePei.inf | 3 +- .../Universal/CapsulePei/UefiCapsule.c | 355 ++++++++++-------- 3 files changed, 192 insertions(+), 169 deletions(-) diff --git a/MdeModulePkg/Universal/CapsulePei/Capsule.h b/MdeModulePkg/Universal/CapsulePei/Capsule.h index baf40423af..fc20dd8b92 100644 --- a/MdeModulePkg/Universal/CapsulePei/Capsule.h +++ b/MdeModulePkg/Universal/CapsulePei/Capsule.h @@ -1,6 +1,6 @@ /** @file -Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent @@ -30,6 +30,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include #include #include +#include #include #include "Common/CommonHeader.h" diff --git a/MdeModulePkg/Universal/CapsulePei/CapsulePei.inf b/MdeModulePkg/Universal/CapsulePei/CapsulePei.inf index 5d43df3075..9c88b3986f 100644 --- a/MdeModulePkg/Universal/CapsulePei/CapsulePei.inf +++ b/MdeModulePkg/Universal/CapsulePei/CapsulePei.inf @@ -6,7 +6,7 @@ # This external input must be validated carefully to avoid security issue like # buffer overflow, integer overflow. # -# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+# Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.
# Copyright (c) 2017, AMD Incorporated. All rights reserved.
# # SPDX-License-Identifier: BSD-2-Clause-Patent @@ -43,6 +43,7 @@ BaseLib HobLib BaseMemoryLib + MemoryAllocationLib PeiServicesLib PeimEntryPoint DebugLib diff --git a/MdeModulePkg/Universal/CapsulePei/UefiCapsule.c b/MdeModulePkg/Universal/CapsulePei/UefiCapsule.c index e967599e96..b3014478a3 100644 --- a/MdeModulePkg/Universal/CapsulePei/UefiCapsule.c +++ b/MdeModulePkg/Universal/CapsulePei/UefiCapsule.c @@ -1,7 +1,7 @@ /** @file Capsule update PEIM for UEFI2.0 -Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.
Copyright (c) 2017, AMD Incorporated. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent @@ -10,6 +10,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include "Capsule.h" +#define DEFAULT_SG_LIST_HEADS (20) + #ifdef MDE_CPU_IA32 // // Global Descriptor Table (GDT) @@ -791,30 +793,87 @@ BuildMemoryResourceDescriptor ( } /** - Checks for the presence of capsule descriptors. - Get capsule descriptors from variable CapsuleUpdateData, CapsuleUpdateData1, CapsuleUpdateData2... - and save to DescriptorBuffer. + Check if the capsules are staged. - @param DescriptorBuffer Pointer to the capsule descriptors + @retval TRUE The capsules are staged. + @retval FALSE The capsules are not staged. + +**/ +BOOLEAN +AreCapsulesStaged ( + VOID + ) +{ + EFI_STATUS Status; + UINTN Size; + EFI_PEI_READ_ONLY_VARIABLE2_PPI *PPIVariableServices; + EFI_PHYSICAL_ADDRESS CapsuleDataPtr64; + + CapsuleDataPtr64 = 0; + + Status = PeiServicesLocatePpi ( + &gEfiPeiReadOnlyVariable2PpiGuid, + 0, + NULL, + (VOID **)&PPIVariableServices + ); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed to find ReadOnlyVariable2PPI\n")); + return FALSE; + } + + // + // Check for Update capsule + // + Size = sizeof (CapsuleDataPtr64); + Status = PPIVariableServices->GetVariable( + PPIVariableServices, + EFI_CAPSULE_VARIABLE_NAME, + &gEfiCapsuleVendorGuid, + NULL, + &Size, + (VOID *)&CapsuleDataPtr64 + ); + + if (!EFI_ERROR (Status)) { + return TRUE; + } + + return FALSE; +} + +/** + Check all the variables for SG list heads and get the count and addresses. + + @param ListLength A pointer would return the SG list length. + @param HeadList A ponter to the capsule SG list. + + @retval EFI_SUCCESS a valid capsule is present + @retval EFI_NOT_FOUND if a valid capsule is not present + @retval EFI_INVALID_PARAMETER the input parameter is invalid + @retval EFI_OUT_OF_RESOURCE fail to allocate memory - @retval EFI_SUCCESS a valid capsule is present - @retval EFI_NOT_FOUND if a valid capsule is not present **/ EFI_STATUS -GetCapsuleDescriptors ( - IN EFI_PHYSICAL_ADDRESS *DescriptorBuffer +GetScatterGatherHeadEntries ( + OUT UINTN *ListLength, + OUT EFI_PHYSICAL_ADDRESS **HeadList ) { - EFI_STATUS Status; - UINTN Size; - UINTN Index; - UINTN TempIndex; - UINTN ValidIndex; - BOOLEAN Flag; - CHAR16 CapsuleVarName[30]; - CHAR16 *TempVarName; - EFI_PHYSICAL_ADDRESS CapsuleDataPtr64; - EFI_PEI_READ_ONLY_VARIABLE2_PPI *PPIVariableServices; + EFI_STATUS Status; + UINTN Size; + UINTN Index; + UINTN TempIndex; + UINTN ValidIndex; + BOOLEAN Flag; + CHAR16 CapsuleVarName[30]; + CHAR16 *TempVarName; + EFI_PHYSICAL_ADDRESS CapsuleDataPtr64; + EFI_PEI_READ_ONLY_VARIABLE2_PPI *PPIVariableServices; + EFI_PHYSICAL_ADDRESS *TempList; + EFI_PHYSICAL_ADDRESS *EnlargedTempList; + UINTN TempListLength; Index = 0; TempVarName = NULL; @@ -822,87 +881,118 @@ GetCapsuleDescriptors ( ValidIndex = 0; CapsuleDataPtr64 = 0; + if ((ListLength == NULL) || (HeadList == NULL)) { + DEBUG ((DEBUG_ERROR, "%a Invalid parameters. Inputs can't be NULL\n", __FUNCTION__)); + ASSERT (ListLength != NULL); + ASSERT (HeadList != NULL); + return EFI_INVALID_PARAMETER; + } + + *ListLength = 0; + *HeadList = NULL; + Status = PeiServicesLocatePpi ( &gEfiPeiReadOnlyVariable2PpiGuid, 0, NULL, (VOID **) &PPIVariableServices ); - if (Status == EFI_SUCCESS) { - StrCpyS (CapsuleVarName, sizeof(CapsuleVarName)/sizeof(CHAR16), EFI_CAPSULE_VARIABLE_NAME); - TempVarName = CapsuleVarName + StrLen (CapsuleVarName); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed to find ReadOnlyVariable2PPI: %r\n", Status)); + return Status; + } + + // + // Allocate memory for sg list head + // + TempListLength = DEFAULT_SG_LIST_HEADS * sizeof (EFI_PHYSICAL_ADDRESS); + TempList = AllocateZeroPool (TempListLength); + if (TempList == NULL) { + DEBUG((DEBUG_ERROR, "Failed to allocate memory\n")); + return EFI_OUT_OF_RESOURCES; + } + + // + // Setup var name buffer for update capsules + // + StrCpyS (CapsuleVarName, sizeof (CapsuleVarName) / sizeof (CHAR16), EFI_CAPSULE_VARIABLE_NAME); + TempVarName = CapsuleVarName + StrLen (CapsuleVarName); + while (TRUE) { + if (Index != 0) { + UnicodeValueToStringS ( + TempVarName, + (sizeof(CapsuleVarName) - ((StrLen(CapsuleVarName) + 1) * sizeof(CHAR16))), + 0, + Index, + 0 + ); + } + Size = sizeof (CapsuleDataPtr64); - while (1) { - if (Index == 0) { - // - // For the first Capsule Image - // - Status = PPIVariableServices->GetVariable ( - PPIVariableServices, - CapsuleVarName, - &gEfiCapsuleVendorGuid, - NULL, - &Size, - (VOID *) &CapsuleDataPtr64 - ); - if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_INFO, "Capsule -- capsule variable not set\n")); - return EFI_NOT_FOUND; - } - // - // We have a chicken/egg situation where the memory init code needs to - // know the boot mode prior to initializing memory. For this case, our - // validate function will fail. We can detect if this is the case if blocklist - // pointer is null. In that case, return success since we know that the - // variable is set. - // - if (DescriptorBuffer == NULL) { - return EFI_SUCCESS; - } - } else { - UnicodeValueToStringS ( - TempVarName, - sizeof (CapsuleVarName) - ((UINTN)TempVarName - (UINTN)CapsuleVarName), - 0, - Index, - 0 - ); - Status = PPIVariableServices->GetVariable ( - PPIVariableServices, - CapsuleVarName, - &gEfiCapsuleVendorGuid, - NULL, - &Size, - (VOID *) &CapsuleDataPtr64 - ); - if (EFI_ERROR (Status)) { - break; - } + Status = PPIVariableServices->GetVariable ( + PPIVariableServices, + CapsuleVarName, + &gEfiCapsuleVendorGuid, + NULL, + &Size, + (VOID *)&CapsuleDataPtr64 + ); - // - // If this BlockList has been linked before, skip this variable - // - Flag = FALSE; - for (TempIndex = 0; TempIndex < ValidIndex; TempIndex++) { - if (DescriptorBuffer[TempIndex] == CapsuleDataPtr64) { - Flag = TRUE; - break; - } - } - if (Flag) { - Index ++; - continue; - } + if (EFI_ERROR (Status)) { + if (Status != EFI_NOT_FOUND) { + DEBUG ((DEBUG_ERROR, "Unexpected error getting Capsule Update variable. Status = %r\n")); + } + break; + } + + // + // If this BlockList has been linked before, skip this variable + // + Flag = FALSE; + for (TempIndex = 0; TempIndex < ValidIndex; TempIndex++) { + if (TempList[TempIndex] == CapsuleDataPtr64) { + Flag = TRUE; + break; } + } + if (Flag) { + Index++; + continue; + } - // - // Cache BlockList which has been processed - // - DescriptorBuffer[ValidIndex++] = CapsuleDataPtr64; - Index ++; + // + // The TempList is full, enlarge it + // + if ((ValidIndex + 1) >= TempListLength) { + EnlargedTempList = AllocateZeroPool (TempListLength * 2); + CopyMem (EnlargedTempList, TempList, TempListLength); + FreePool (TempList); + TempList = EnlargedTempList; + TempListLength *= 2; } + + // + // Cache BlockList which has been processed + // + TempList[ValidIndex++] = CapsuleDataPtr64; + Index++; + } + + if (ValidIndex == 0) { + DEBUG((DEBUG_ERROR, "%a didn't find any SG lists in variables\n", __FUNCTION__)); + return EFI_NOT_FOUND; } + *HeadList = AllocateZeroPool ((ValidIndex + 1) * sizeof (EFI_PHYSICAL_ADDRESS)); + if (*HeadList == NULL) { + DEBUG((DEBUG_ERROR, "Failed to allocate memory\n")); + return EFI_OUT_OF_RESOURCES; + } + + CopyMem (*HeadList, TempList, (ValidIndex) * sizeof (EFI_PHYSICAL_ADDRESS)); + *ListLength = ValidIndex; + return EFI_SUCCESS; } @@ -937,17 +1027,11 @@ CapsuleCoalesce ( IN OUT UINTN *MemorySize ) { - UINTN Index; - UINTN Size; - UINTN VariableCount; - CHAR16 CapsuleVarName[30]; - CHAR16 *TempVarName; - EFI_PHYSICAL_ADDRESS CapsuleDataPtr64; EFI_STATUS Status; EFI_BOOT_MODE BootMode; - EFI_PEI_READ_ONLY_VARIABLE2_PPI *PPIVariableServices; EFI_PHYSICAL_ADDRESS *VariableArrayAddress; MEMORY_RESOURCE_DESCRIPTOR *MemoryResource; + UINTN ListLength; #ifdef MDE_CPU_IA32 UINT16 CoalesceImageMachineType; EFI_PHYSICAL_ADDRESS CoalesceImageEntryPoint; @@ -955,10 +1039,8 @@ CapsuleCoalesce ( EFI_CAPSULE_LONG_MODE_BUFFER LongModeBuffer; #endif - Index = 0; - VariableCount = 0; - CapsuleVarName[0] = 0; - CapsuleDataPtr64 = 0; + ListLength = 0; + VariableArrayAddress = NULL; // // Someone should have already ascertained the boot mode. If it's not @@ -972,74 +1054,11 @@ CapsuleCoalesce ( } // - // User may set the same ScatterGatherList with several different variables, - // so cache all ScatterGatherList for check later. - // - Status = PeiServicesLocatePpi ( - &gEfiPeiReadOnlyVariable2PpiGuid, - 0, - NULL, - (VOID **) &PPIVariableServices - ); - if (EFI_ERROR (Status)) { - goto Done; - } - Size = sizeof (CapsuleDataPtr64); - StrCpyS (CapsuleVarName, sizeof(CapsuleVarName)/sizeof(CHAR16), EFI_CAPSULE_VARIABLE_NAME); - TempVarName = CapsuleVarName + StrLen (CapsuleVarName); - while (TRUE) { - if (Index > 0) { - UnicodeValueToStringS ( - TempVarName, - sizeof (CapsuleVarName) - ((UINTN)TempVarName - (UINTN)CapsuleVarName), - 0, - Index, - 0 - ); - } - Status = PPIVariableServices->GetVariable ( - PPIVariableServices, - CapsuleVarName, - &gEfiCapsuleVendorGuid, - NULL, - &Size, - (VOID *) &CapsuleDataPtr64 - ); - if (EFI_ERROR (Status)) { - // - // There is no capsule variables, quit - // - DEBUG ((DEBUG_INFO,"Capsule variable Index = %d\n", Index)); - break; - } - VariableCount++; - Index++; - } - - DEBUG ((DEBUG_INFO,"Capsule variable count = %d\n", VariableCount)); - - // - // The last entry is the end flag. - // - Status = PeiServicesAllocatePool ( - (VariableCount + 1) * sizeof (EFI_PHYSICAL_ADDRESS), - (VOID **)&VariableArrayAddress - ); - - if (Status != EFI_SUCCESS) { - DEBUG ((DEBUG_ERROR, "AllocatePages Failed!, Status = %x\n", Status)); - goto Done; - } - - ZeroMem (VariableArrayAddress, (VariableCount + 1) * sizeof (EFI_PHYSICAL_ADDRESS)); - - // - // Find out if we actually have a capsule. - // GetCapsuleDescriptors depends on variable PPI, so it should run in 32-bit environment. + // Get ScatterGatherList // - Status = GetCapsuleDescriptors (VariableArrayAddress); + Status = GetScatterGatherHeadEntries (&ListLength, &VariableArrayAddress); if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_ERROR, "Fail to find capsule variables.\n")); + DEBUG ((DEBUG_ERROR, "%a failed to get Scatter Gather List Head Entries. Status = %r\n", __FUNCTION__, Status)); goto Done; } @@ -1117,9 +1136,11 @@ CheckCapsuleUpdate ( IN EFI_PEI_SERVICES **PeiServices ) { - EFI_STATUS Status; - Status = GetCapsuleDescriptors (NULL); - return Status; + if (AreCapsulesStaged ()) { + return EFI_SUCCESS; + } else { + return EFI_NOT_FOUND; + } } /** This function will look at a capsule and determine if it's a test pattern. -- 2.21.0.windows.1