diff --git a/SecurityPkg/SecurityPkg.dsc b/SecurityPkg/SecurityPkg.dsc index 804da7077c..0600a5f141 100644 --- a/SecurityPkg/SecurityPkg.dsc +++ b/SecurityPkg/SecurityPkg.dsc @@ -64,6 +64,7 @@ ReportStatusCodeLib|MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf [LibraryClasses.common.UEFI_DRIVER, LibraryClasses.common.DXE_RUNTIME_DRIVER, LibraryClasses.common.DXE_SAL_DRIVER,] + HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf DebugLib|MdePkg/Library/UefiDebugLibConOut/UefiDebugLibConOut.inf @@ -71,6 +72,7 @@ ExtendedSalLib|MdePkg/Library/DxeRuntimeExtendedSalLib/DxeRuntimeExtendedSalLib.inf [LibraryClasses.common.DXE_SMM_DRIVER] + HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf SmmServicesTableLib|MdePkg/Library/SmmServicesTableLib/SmmServicesTableLib.inf MemoryAllocationLib|MdePkg/Library/SmmMemoryAllocationLib/SmmMemoryAllocationLib.inf BaseCryptLib|CryptoPkg/Library/BaseCryptLib/SmmCryptLib.inf diff --git a/SecurityPkg/VariableAuthenticated/Pei/Variable.c b/SecurityPkg/VariableAuthenticated/Pei/Variable.c index f637675157..240bc8aa43 100644 --- a/SecurityPkg/VariableAuthenticated/Pei/Variable.c +++ b/SecurityPkg/VariableAuthenticated/Pei/Variable.c @@ -31,33 +31,6 @@ EFI_PEI_PPI_DESCRIPTOR mPpiListVariable = { &mVariablePpi }; - -/** - Check if it runs in Recovery mode. - - @param PeiServices General purpose services available to every PEIM. - - @retval TRUE It's in Recovery mode. - @retval FALSE It's not in Recovery mode. - -**/ -BOOLEAN -IsInRecoveryMode ( - IN CONST EFI_PEI_SERVICES **PeiServices - ) -{ - EFI_STATUS Status; - EFI_BOOT_MODE BootMode; - - Status = (*PeiServices)->GetBootMode (PeiServices, &BootMode); - ASSERT_EFI_ERROR (Status); - - if (BootMode == BOOT_IN_RECOVERY_MODE) { - return TRUE; - } - return FALSE; -} - /** Provide the functionality of the variable services. @@ -67,7 +40,6 @@ IsInRecoveryMode ( @retval EFI_SUCCESS If the interface could be successfully installed @retval Others Returned from PeiServicesInstallPpi() - **/ EFI_STATUS EFIAPI @@ -348,14 +320,84 @@ CompareWithValidVariable ( return EFI_NOT_FOUND; } +/** + Return the variable store header and the index table based on the Index. + + @param Index The index of the variable store. + @param IndexTable Return the index table. + + @return Pointer to the variable store header. +**/ +VARIABLE_STORE_HEADER * +GetVariableStore ( + IN VARIABLE_STORE_TYPE Type, + OUT VARIABLE_INDEX_TABLE **IndexTable OPTIONAL + ) +{ + EFI_HOB_GUID_TYPE *GuidHob; + EFI_FIRMWARE_VOLUME_HEADER *FvHeader; + VARIABLE_STORE_HEADER *VariableStoreHeader; + + if (IndexTable != NULL) { + *IndexTable = NULL; + } + VariableStoreHeader = NULL; + switch (Type) { + case VariableStoreTypeHob: + GuidHob = GetFirstGuidHob (&gEfiAuthenticatedVariableGuid); + if (GuidHob != NULL) { + VariableStoreHeader = (VARIABLE_STORE_HEADER *) GET_GUID_HOB_DATA (GuidHob); + } + break; + + case VariableStoreTypeNv: + if (GetBootModeHob () != BOOT_IN_RECOVERY_MODE) { + // + // The content of NV storage for variable is not reliable in recovery boot mode. + // + FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) (PcdGet64 (PcdFlashNvStorageVariableBase64) != 0 ? + PcdGet64 (PcdFlashNvStorageVariableBase64) : + PcdGet32 (PcdFlashNvStorageVariableBase) + ); + VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINT8 *) FvHeader + FvHeader->HeaderLength); + + if (IndexTable != NULL) { + GuidHob = GetFirstGuidHob (&gEfiVariableIndexTableGuid); + if (GuidHob != NULL) { + *IndexTable = GET_GUID_HOB_DATA (GuidHob); + } else { + // + // If it's the first time to access variable region in flash, create a guid hob to record + // VAR_ADDED type variable info. + // Note that as the resource of PEI phase is limited, only store the limited number of + // VAR_ADDED type variables to reduce access time. + // + *IndexTable = BuildGuidHob (&gEfiVariableIndexTableGuid, sizeof (VARIABLE_INDEX_TABLE)); + (*IndexTable)->Length = 0; + (*IndexTable)->StartPtr = GetStartPointer (VariableStoreHeader); + (*IndexTable)->EndPtr = GetEndPointer (VariableStoreHeader); + (*IndexTable)->GoneThrough = 0; + } + } + } + break; + + default: + ASSERT (FALSE); + break; + } + + return VariableStoreHeader; +} /** - This code finds variable in storage blocks (Non-Volatile). + Find the variable in the specified variable store. - @param PeiServices General purpose services available to every PEIM. - @param VariableName Name of the variable to be found - @param VendorGuid Vendor GUID to be found. - @param PtrTrack Variable Track Pointer structure that contains Variable Information. + @param VariableStoreHeader Pointer to the variable store header. + @param IndexTable Pointer to the index table. + @param VariableName Name of the variable to be found + @param VendorGuid Vendor GUID to be found. + @param PtrTrack Variable Track Pointer structure that contains Variable Information. @retval EFI_SUCCESS Variable found successfully @retval EFI_NOT_FOUND Variable not found @@ -363,134 +405,100 @@ CompareWithValidVariable ( **/ EFI_STATUS -FindVariable ( - IN CONST EFI_PEI_SERVICES **PeiServices, - IN CONST CHAR16 *VariableName, - IN CONST EFI_GUID *VendorGuid, - OUT VARIABLE_POINTER_TRACK *PtrTrack +FindVariableEx ( + IN VARIABLE_STORE_HEADER *VariableStoreHeader, + IN VARIABLE_INDEX_TABLE *IndexTable, + IN CONST CHAR16 *VariableName, + IN CONST EFI_GUID *VendorGuid, + OUT VARIABLE_POINTER_TRACK *PtrTrack ) { - EFI_HOB_GUID_TYPE *GuidHob; - VARIABLE_STORE_HEADER *VariableStoreHeader; VARIABLE_HEADER *Variable; VARIABLE_HEADER *LastVariable; VARIABLE_HEADER *MaxIndex; - VARIABLE_INDEX_TABLE *IndexTable; - UINT32 Count; - UINT32 Offset; - UINT8 *VariableBase; + UINTN Index; + UINTN Offset; BOOLEAN StopRecord; - if (VariableName[0] != 0 && VendorGuid == NULL) { + if (VariableStoreHeader == NULL) { return EFI_INVALID_PARAMETER; } + + if (GetVariableStoreStatus (VariableStoreHeader) != EfiValid) { + return EFI_UNSUPPORTED; + } + + if (~VariableStoreHeader->Size == 0) { + return EFI_NOT_FOUND; + } + + PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader); + PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader); + // // No Variable Address equals zero, so 0 as initial value is safe. // - MaxIndex = 0; - StopRecord = FALSE; + MaxIndex = NULL; - GuidHob = GetFirstGuidHob (&gEfiVariableIndexTableGuid); - if (GuidHob == NULL) { + if (IndexTable != NULL) { // - // If it's the first time to access variable region in flash, create a guid hob to record - // VAR_ADDED type variable info. - // Note that as the resource of PEI phase is limited, only store the number of - // VARIABLE_INDEX_TABLE_VOLUME of VAR_ADDED type variables to reduce access time. + // traverse the variable index table to look for varible. + // The IndexTable->Index[Index] records the distance of two neighbouring VAR_ADDED type variables. // - IndexTable = BuildGuidHob (&gEfiVariableIndexTableGuid, sizeof (VARIABLE_INDEX_TABLE)); - IndexTable->Length = 0; - IndexTable->StartPtr = NULL; - IndexTable->EndPtr = NULL; - IndexTable->GoneThrough = 0; - } else { - IndexTable = GET_GUID_HOB_DATA (GuidHob); - for (Offset = 0, Count = 0; Count < IndexTable->Length; Count++) { - // - // traverse the variable info list to look for varible. - // The IndexTable->Index[Count] records the distance of two neighbouring VAR_ADDED type variables. - // - ASSERT (Count < VARIABLE_INDEX_TABLE_VOLUME); - Offset += IndexTable->Index[Count]; - MaxIndex = (VARIABLE_HEADER *)((CHAR8 *)(IndexTable->StartPtr) + Offset); + for (Offset = 0, Index = 0; Index < IndexTable->Length; Index++) { + ASSERT (Index < sizeof (IndexTable->Index) / sizeof (IndexTable->Index[0])); + Offset += IndexTable->Index[Index]; + MaxIndex = (VARIABLE_HEADER *) ((UINT8 *) IndexTable->StartPtr + Offset); if (CompareWithValidVariable (MaxIndex, VariableName, VendorGuid, PtrTrack) == EFI_SUCCESS) { - PtrTrack->StartPtr = IndexTable->StartPtr; - PtrTrack->EndPtr = IndexTable->EndPtr; - return EFI_SUCCESS; } } if (IndexTable->GoneThrough != 0) { + // + // If the table has all the existing variables indexed and we still cannot find it. + // return EFI_NOT_FOUND; } } - // - // If not found in HOB, then let's start from the MaxIndex we've found. - // + if (MaxIndex != NULL) { + // + // HOB exists but the variable cannot be found in HOB + // If not found in HOB, then let's start from the MaxIndex we've found. + // Variable = GetNextVariablePtr (MaxIndex); LastVariable = MaxIndex; } else { - if ((IndexTable->StartPtr != NULL) || (IndexTable->EndPtr != NULL)) { - Variable = IndexTable->StartPtr; - } else { - VariableBase = (UINT8 *) (UINTN) PcdGet64 (PcdFlashNvStorageVariableBase64); - if (VariableBase == NULL) { - VariableBase = (UINT8 *) (UINTN) PcdGet32 (PcdFlashNvStorageVariableBase); - } - - VariableStoreHeader = (VARIABLE_STORE_HEADER *) (VariableBase + \ - ((EFI_FIRMWARE_VOLUME_HEADER *) (VariableBase)) -> HeaderLength); - - if (GetVariableStoreStatus (VariableStoreHeader) != EfiValid) { - return EFI_UNSUPPORTED; - } - - if (~VariableStoreHeader->Size == 0) { - return EFI_NOT_FOUND; - } - // - // Find the variable by walk through non-volatile variable store - // - IndexTable->StartPtr = GetStartPointer (VariableStoreHeader); - IndexTable->EndPtr = GetEndPointer (VariableStoreHeader); - - // - // Start Pointers for the variable. - // Actual Data Pointer where data can be written. - // - Variable = IndexTable->StartPtr; - } - - LastVariable = IndexTable->StartPtr; + // + // Start Pointers for the variable. + // Actual Data Pointer where data can be written. + // + Variable = PtrTrack->StartPtr; + LastVariable = PtrTrack->StartPtr; } + // // Find the variable by walk through non-volatile variable store // - PtrTrack->StartPtr = IndexTable->StartPtr; - PtrTrack->EndPtr = IndexTable->EndPtr; - - while ((Variable < IndexTable->EndPtr) && IsValidVariableHeader (Variable)) { + StopRecord = FALSE; + while ((Variable < PtrTrack->EndPtr) && IsValidVariableHeader (Variable)) { if (Variable->State == VAR_ADDED) { // // Record Variable in VariableIndex HOB // - if (IndexTable->Length < VARIABLE_INDEX_TABLE_VOLUME && !StopRecord) { - Offset = (UINT32)((UINTN)Variable - (UINTN)LastVariable); - // - // The distance of two neighbouring VAR_ADDED variable is larger than 2^16, - // which is beyond the allowable scope(UINT16) of record. In such case, need not to - // record the subsequent VAR_ADDED type variables again. - // - if ((Offset & 0xFFFF0000UL) != 0) { + if ((IndexTable != NULL) && !StopRecord) { + Offset = (UINTN) Variable - (UINTN) LastVariable; + if ((Offset > 0x0FFFF) || (IndexTable->Length == sizeof (IndexTable->Index) / sizeof (IndexTable->Index[0]))) { + // + // Stop to record if the distance of two neighbouring VAR_ADDED variable is larger than the allowable scope(UINT16), + // or the record buffer is full. + // StopRecord = TRUE; - } - - if (!StopRecord) { + } else { IndexTable->Index[IndexTable->Length++] = (UINT16) Offset; + LastVariable = Variable; } - LastVariable = Variable; } if (CompareWithValidVariable (Variable, VariableName, VendorGuid, PtrTrack) == EFI_SUCCESS) { @@ -503,7 +511,7 @@ FindVariable ( // // If gone through the VariableStore, that means we never find in Firmware any more. // - if ((IndexTable->Length < VARIABLE_INDEX_TABLE_VOLUME) && (!StopRecord)) { + if ((IndexTable != NULL) && !StopRecord) { IndexTable->GoneThrough = 1; } @@ -512,6 +520,50 @@ FindVariable ( return EFI_NOT_FOUND; } +/** + Find the variable in HOB and Non-Volatile variable storages. + + @param VariableName Name of the variable to be found + @param VendorGuid Vendor GUID to be found. + @param PtrTrack Variable Track Pointer structure that contains Variable Information. + + @retval EFI_SUCCESS Variable found successfully + @retval EFI_NOT_FOUND Variable not found + @retval EFI_INVALID_PARAMETER Invalid variable name +**/ +EFI_STATUS +FindVariable ( + IN CONST CHAR16 *VariableName, + IN CONST EFI_GUID *VendorGuid, + OUT VARIABLE_POINTER_TRACK *PtrTrack + ) +{ + EFI_STATUS Status; + VARIABLE_STORE_HEADER *VariableStoreHeader; + VARIABLE_INDEX_TABLE *IndexTable; + VARIABLE_STORE_TYPE Type; + + if (VariableName[0] != 0 && VendorGuid == NULL) { + return EFI_INVALID_PARAMETER; + } + + for (Type = (VARIABLE_STORE_TYPE) 0; Type < VariableStoreTypeMax; Type++) { + VariableStoreHeader = GetVariableStore (Type, &IndexTable); + Status = FindVariableEx ( + VariableStoreHeader, + IndexTable, + VariableName, + VendorGuid, + PtrTrack + ); + if (!EFI_ERROR (Status)) { + return Status; + } + } + + return EFI_NOT_FOUND; +} + /** This service retrieves a variable's value using its name and GUID. @@ -552,27 +604,16 @@ PeiGetVariable ( VARIABLE_POINTER_TRACK Variable; UINTN VarDataSize; EFI_STATUS Status; - CONST EFI_PEI_SERVICES **PeiServices; - PeiServices = GetPeiServicesTablePointer (); if (VariableName == NULL || VariableGuid == NULL || DataSize == NULL) { return EFI_INVALID_PARAMETER; } - // - // Check if this is recovery boot path. - // If yes, the content of variable area is not reliable. Therefore we directly - // return EFI_NOT_FOUND. - // - if (IsInRecoveryMode(PeiServices)) { - return EFI_NOT_FOUND; - } - // // Find existing variable // - Status = FindVariable (PeiServices, VariableName, VariableGuid, &Variable); - if (Variable.CurrPtr == NULL || Status != EFI_SUCCESS) { + Status = FindVariable (VariableName, VariableGuid, &Variable); + if (EFI_ERROR (Status)) { return Status; } // @@ -636,26 +677,18 @@ PeiGetNextVariableName ( IN OUT EFI_GUID *VariableGuid ) { + VARIABLE_STORE_TYPE Type; VARIABLE_POINTER_TRACK Variable; + VARIABLE_POINTER_TRACK VariableInHob; UINTN VarNameSize; EFI_STATUS Status; - CONST EFI_PEI_SERVICES **PeiServices; + VARIABLE_STORE_HEADER *VariableStoreHeader[VariableStoreTypeMax]; - PeiServices = GetPeiServicesTablePointer (); if (VariableName == NULL || VariableGuid == NULL || VariableNameSize == NULL) { return EFI_INVALID_PARAMETER; } - // - // Check if this is recovery boot path. - // If yes, the content of variable area is not reliable. Therefore we directly - // return EFI_NOT_FOUND. - // - if (IsInRecoveryMode(PeiServices)) { - return EFI_NOT_FOUND; - } - - Status = FindVariable (PeiServices, VariableName, VariableGuid, &Variable); + Status = FindVariable (VariableName, VariableGuid, &Variable); if (Variable.CurrPtr == NULL || Status != EFI_SUCCESS) { return Status; } @@ -667,34 +700,88 @@ PeiGetNextVariableName ( Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr); } - while (!(Variable.CurrPtr >= Variable.EndPtr || Variable.CurrPtr == NULL)) { - if (IsValidVariableHeader (Variable.CurrPtr)) { - if (Variable.CurrPtr->State == VAR_ADDED) { - ASSERT (NameSizeOfVariable (Variable.CurrPtr) != 0); + VariableStoreHeader[VariableStoreTypeHob] = GetVariableStore (VariableStoreTypeHob, NULL); + VariableStoreHeader[VariableStoreTypeNv] = GetVariableStore (VariableStoreTypeNv, NULL); - VarNameSize = (UINTN) NameSizeOfVariable (Variable.CurrPtr); - if (VarNameSize <= *VariableNameSize) { - CopyMem (VariableName, GetVariableNamePtr (Variable.CurrPtr), VarNameSize); - - CopyMem (VariableGuid, &Variable.CurrPtr->VendorGuid, sizeof (EFI_GUID)); - - Status = EFI_SUCCESS; - } else { - Status = EFI_BUFFER_TOO_SMALL; + while (TRUE) { + // + // Switch from HOB to Non-Volatile. + // + while ((Variable.CurrPtr >= Variable.EndPtr) || + (Variable.CurrPtr == NULL) || + !IsValidVariableHeader (Variable.CurrPtr) + ) { + // + // Find current storage index + // + for (Type = (VARIABLE_STORE_TYPE) 0; Type < VariableStoreTypeMax; Type++) { + if ((VariableStoreHeader[Type] != NULL) && (Variable.StartPtr == GetStartPointer (VariableStoreHeader[Type]))) { + break; } - - *VariableNameSize = VarNameSize; - return Status; - // - // Variable is found - // - } else { - Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr); } + ASSERT (Type < VariableStoreTypeMax); + // + // Switch to next storage + // + for (Type++; Type < VariableStoreTypeMax; Type++) { + if (VariableStoreHeader[Type] != NULL) { + break; + } + } + // + // Capture the case that + // 1. current storage is the last one, or + // 2. no further storage + // + if (Type == VariableStoreTypeMax) { + return EFI_NOT_FOUND; + } + Variable.StartPtr = GetStartPointer (VariableStoreHeader[Type]); + Variable.EndPtr = GetEndPointer (VariableStoreHeader[Type]); + Variable.CurrPtr = Variable.StartPtr; + } + + if (Variable.CurrPtr->State == VAR_ADDED) { + + // + // Don't return NV variable when HOB overrides it + // + if ((VariableStoreHeader[VariableStoreTypeHob] != NULL) && (VariableStoreHeader[VariableStoreTypeNv] != NULL) && + (Variable.StartPtr == GetStartPointer (VariableStoreHeader[VariableStoreTypeNv])) + ) { + Status = FindVariableEx ( + VariableStoreHeader[VariableStoreTypeHob], + NULL, + GetVariableNamePtr (Variable.CurrPtr), + &Variable.CurrPtr->VendorGuid, + &VariableInHob + ); + if (!EFI_ERROR (Status)) { + Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr); + continue; + } + } + + VarNameSize = NameSizeOfVariable (Variable.CurrPtr); + ASSERT (VarNameSize != 0); + + if (VarNameSize <= *VariableNameSize) { + CopyMem (VariableName, GetVariableNamePtr (Variable.CurrPtr), VarNameSize); + + CopyMem (VariableGuid, &Variable.CurrPtr->VendorGuid, sizeof (EFI_GUID)); + + Status = EFI_SUCCESS; + } else { + Status = EFI_BUFFER_TOO_SMALL; + } + + *VariableNameSize = VarNameSize; + // + // Variable is found + // + return Status; } else { - break; + Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr); } } - - return EFI_NOT_FOUND; } diff --git a/SecurityPkg/VariableAuthenticated/Pei/Variable.h b/SecurityPkg/VariableAuthenticated/Pei/Variable.h index af22687fe8..75d32dac5f 100644 --- a/SecurityPkg/VariableAuthenticated/Pei/Variable.h +++ b/SecurityPkg/VariableAuthenticated/Pei/Variable.h @@ -29,6 +29,13 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include #include + +typedef enum { + VariableStoreTypeHob, + VariableStoreTypeNv, + VariableStoreTypeMax +} VARIABLE_STORE_TYPE; + // // Functions // diff --git a/SecurityPkg/VariableAuthenticated/RuntimeDxe/Variable.c b/SecurityPkg/VariableAuthenticated/RuntimeDxe/Variable.c index 0846b2a21b..32bddbcb02 100644 --- a/SecurityPkg/VariableAuthenticated/RuntimeDxe/Variable.c +++ b/SecurityPkg/VariableAuthenticated/RuntimeDxe/Variable.c @@ -715,6 +715,67 @@ Reclaim ( return Status; } +/** + Find the variable in the specified variable store. + + @param VariableName Name of the variable to be found + @param VendorGuid Vendor GUID to be found. + @param PtrTrack Variable Track Pointer structure that contains Variable Information. + + @retval EFI_SUCCESS Variable found successfully + @retval EFI_NOT_FOUND Variable not found +**/ +EFI_STATUS +FindVariableEx ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN OUT VARIABLE_POINTER_TRACK *PtrTrack + ) +{ + VARIABLE_HEADER *InDeletedVariable; + VOID *Point; + + // + // Find the variable by walk through HOB, volatile and non-volatile variable store. + // + InDeletedVariable = NULL; + + for ( PtrTrack->CurrPtr = PtrTrack->StartPtr + ; (PtrTrack->CurrPtr < PtrTrack->EndPtr) && IsValidVariableHeader (PtrTrack->CurrPtr) + ; PtrTrack->CurrPtr = GetNextVariablePtr (PtrTrack->CurrPtr) + ) { + if (PtrTrack->CurrPtr->State == VAR_ADDED || + PtrTrack->CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED) + ) { + if (!AtRuntime () || ((PtrTrack->CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) != 0)) { + if (VariableName[0] == 0) { + if (PtrTrack->CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) { + InDeletedVariable = PtrTrack->CurrPtr; + } else { + return EFI_SUCCESS; + } + } else { + if (CompareGuid (VendorGuid, &PtrTrack->CurrPtr->VendorGuid)) { + Point = (VOID *) GetVariableNamePtr (PtrTrack->CurrPtr); + + ASSERT (NameSizeOfVariable (PtrTrack->CurrPtr) != 0); + if (CompareMem (VariableName, Point, NameSizeOfVariable (PtrTrack->CurrPtr)) == 0) { + if (PtrTrack->CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) { + InDeletedVariable = PtrTrack->CurrPtr; + } else { + return EFI_SUCCESS; + } + } + } + } + } + } + } + + PtrTrack->CurrPtr = InDeletedVariable; + return (PtrTrack->CurrPtr == NULL) ? EFI_NOT_FOUND : EFI_SUCCESS; +} + /** Finds variable in storage blocks of volatile and non-volatile storage areas. @@ -746,89 +807,40 @@ FindVariable ( IN VARIABLE_GLOBAL *Global ) { - VARIABLE_HEADER *Variable[2]; - VARIABLE_HEADER *InDeletedVariable; - VARIABLE_STORE_HEADER *VariableStoreHeader[2]; - UINTN InDeletedStorageIndex; - UINTN Index; - VOID *Point; - - // - // 0: Volatile, 1: Non-Volatile. - // The index and attributes mapping must be kept in this order as RuntimeServiceGetNextVariableName - // make use of this mapping to implement search algorithm. - // - VariableStoreHeader[0] = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase); - VariableStoreHeader[1] = mNvVariableCache; - - // - // Start Pointers for the variable. - // Actual Data Pointer where data can be written. - // - Variable[0] = GetStartPointer (VariableStoreHeader[0]); - Variable[1] = GetStartPointer (VariableStoreHeader[1]); + EFI_STATUS Status; + VARIABLE_STORE_HEADER *VariableStoreHeader[VariableStoreTypeMax]; + VARIABLE_STORE_TYPE Type; if (VariableName[0] != 0 && VendorGuid == NULL) { return EFI_INVALID_PARAMETER; } // - // Find the variable by walk through volatile and then non-volatile variable store. + // 0: Volatile, 1: HOB, 2: Non-Volatile. + // The index and attributes mapping must be kept in this order as RuntimeServiceGetNextVariableName + // make use of this mapping to implement search algorithm. // - InDeletedVariable = NULL; - InDeletedStorageIndex = 0; - for (Index = 0; Index < 2; Index++) { - while ((Variable[Index] < GetEndPointer (VariableStoreHeader[Index])) && IsValidVariableHeader (Variable[Index])) { - if (Variable[Index]->State == VAR_ADDED || - Variable[Index]->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED) - ) { - if (!AtRuntime () || ((Variable[Index]->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) != 0)) { - if (VariableName[0] == 0) { - if (Variable[Index]->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) { - InDeletedVariable = Variable[Index]; - InDeletedStorageIndex = Index; - } else { - PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader[Index]); - PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader[Index]); - PtrTrack->CurrPtr = Variable[Index]; - PtrTrack->Volatile = (BOOLEAN)(Index == 0); + VariableStoreHeader[VariableStoreTypeVolatile] = (VARIABLE_STORE_HEADER *) (UINTN) Global->VolatileVariableBase; + VariableStoreHeader[VariableStoreTypeHob] = (VARIABLE_STORE_HEADER *) (UINTN) Global->HobVariableBase; + VariableStoreHeader[VariableStoreTypeNv] = mNvVariableCache; - return EFI_SUCCESS; - } - } else { - if (CompareGuid (VendorGuid, &Variable[Index]->VendorGuid)) { - Point = (VOID *) GetVariableNamePtr (Variable[Index]); - - ASSERT (NameSizeOfVariable (Variable[Index]) != 0); - if (CompareMem (VariableName, Point, NameSizeOfVariable (Variable[Index])) == 0) { - if (Variable[Index]->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) { - InDeletedVariable = Variable[Index]; - InDeletedStorageIndex = Index; - } else { - PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader[Index]); - PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader[Index]); - PtrTrack->CurrPtr = Variable[Index]; - PtrTrack->Volatile = (BOOLEAN)(Index == 0); - - return EFI_SUCCESS; - } - } - } - } - } - } - - Variable[Index] = GetNextVariablePtr (Variable[Index]); + // + // Find the variable by walk through HOB, volatile and non-volatile variable store. + // + for (Type = (VARIABLE_STORE_TYPE) 0; Type < VariableStoreTypeMax; Type++) { + if (VariableStoreHeader[Type] == NULL) { + continue; } - if (InDeletedVariable != NULL) { - PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader[InDeletedStorageIndex]); - PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader[InDeletedStorageIndex]); - PtrTrack->CurrPtr = InDeletedVariable; - PtrTrack->Volatile = (BOOLEAN)(InDeletedStorageIndex == 0); - return EFI_SUCCESS; + + PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader[Type]); + PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader[Type]); + PtrTrack->Volatile = (BOOLEAN) (Type == VariableStoreTypeVolatile); + + Status = FindVariableEx (VariableName, VendorGuid, PtrTrack); + if (!EFI_ERROR (Status)) { + return Status; } } - PtrTrack->CurrPtr = NULL; return EFI_NOT_FOUND; } @@ -1226,7 +1238,7 @@ AutoUpdateLangVariable( // Update Lang if PlatformLang is already set // Update PlatformLang if Lang is already set // - Status = FindVariable (L"PlatformLang", &gEfiGlobalVariableGuid, &Variable, (VARIABLE_GLOBAL *) mVariableModuleGlobal); + Status = FindVariable (L"PlatformLang", &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal); if (!EFI_ERROR (Status)) { // // Update Lang @@ -1235,7 +1247,7 @@ AutoUpdateLangVariable( Data = GetVariableDataPtr (Variable.CurrPtr); DataSize = Variable.CurrPtr->DataSize; } else { - Status = FindVariable (L"Lang", &gEfiGlobalVariableGuid, &Variable, (VARIABLE_GLOBAL *) mVariableModuleGlobal); + Status = FindVariable (L"Lang", &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal); if (!EFI_ERROR (Status)) { // // Update PlatformLang @@ -1280,7 +1292,7 @@ AutoUpdateLangVariable( // // Successfully convert PlatformLang to Lang, and set the BestLang value into Lang variable simultaneously. // - FindVariable (L"Lang", &gEfiGlobalVariableGuid, &Variable, (VARIABLE_GLOBAL *)mVariableModuleGlobal); + FindVariable (L"Lang", &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal); Status = UpdateVariable (L"Lang", &gEfiGlobalVariableGuid, BestLang, ISO_639_2_ENTRY_SIZE + 1, Attributes, 0, 0, &Variable, NULL); @@ -1314,7 +1326,7 @@ AutoUpdateLangVariable( // // Successfully convert Lang to PlatformLang, and set the BestPlatformLang value into PlatformLang variable simultaneously. // - FindVariable (L"PlatformLang", &gEfiGlobalVariableGuid, &Variable, (VARIABLE_GLOBAL *)mVariableModuleGlobal); + FindVariable (L"PlatformLang", &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal); Status = UpdateVariable (L"PlatformLang", &gEfiGlobalVariableGuid, BestPlatformLang, AsciiStrSize (BestPlatformLang), Attributes, 0, 0, &Variable, NULL); @@ -1935,9 +1947,12 @@ VariableServiceGetNextVariableName ( IN OUT EFI_GUID *VendorGuid ) { + VARIABLE_STORE_TYPE Type; VARIABLE_POINTER_TRACK Variable; + VARIABLE_POINTER_TRACK VariableInHob; UINTN VarNameSize; EFI_STATUS Status; + VARIABLE_STORE_HEADER *VariableStoreHeader[VariableStoreTypeMax]; if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) { return EFI_INVALID_PARAMETER; @@ -1957,45 +1972,85 @@ VariableServiceGetNextVariableName ( Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr); } + // + // 0: Volatile, 1: HOB, 2: Non-Volatile. + // The index and attributes mapping must be kept in this order as FindVariable + // makes use of this mapping to implement search algorithm. + // + VariableStoreHeader[VariableStoreTypeVolatile] = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase; + VariableStoreHeader[VariableStoreTypeHob] = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase; + VariableStoreHeader[VariableStoreTypeNv] = mNvVariableCache; + while (TRUE) { // - // If both volatile and non-volatile variable store are parsed, - // return not found. + // Switch from Volatile to HOB, to Non-Volatile. // - if (Variable.CurrPtr >= Variable.EndPtr || Variable.CurrPtr == NULL) { - Variable.Volatile = (BOOLEAN) (Variable.Volatile ^ ((BOOLEAN) 0x1)); - if (!Variable.Volatile) { - Variable.StartPtr = GetStartPointer ((VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase); - Variable.EndPtr = GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase)); - } else { + while ((Variable.CurrPtr >= Variable.EndPtr) || + (Variable.CurrPtr == NULL) || + !IsValidVariableHeader (Variable.CurrPtr) + ) { + // + // Find current storage index + // + for (Type = (VARIABLE_STORE_TYPE) 0; Type < VariableStoreTypeMax; Type++) { + if ((VariableStoreHeader[Type] != NULL) && (Variable.StartPtr == GetStartPointer (VariableStoreHeader[Type]))) { + break; + } + } + ASSERT (Type < VariableStoreTypeMax); + // + // Switch to next storage + // + for (Type++; Type < VariableStoreTypeMax; Type++) { + if (VariableStoreHeader[Type] != NULL) { + break; + } + } + // + // Capture the case that + // 1. current storage is the last one, or + // 2. no further storage + // + if (Type == VariableStoreTypeMax) { Status = EFI_NOT_FOUND; goto Done; } - - Variable.CurrPtr = Variable.StartPtr; - if (!IsValidVariableHeader (Variable.CurrPtr)) { - continue; - } + Variable.StartPtr = GetStartPointer (VariableStoreHeader[Type]); + Variable.EndPtr = GetEndPointer (VariableStoreHeader[Type]); + Variable.CurrPtr = Variable.StartPtr; } + // // Variable is found // - if (IsValidVariableHeader (Variable.CurrPtr) && Variable.CurrPtr->State == VAR_ADDED) { + if (Variable.CurrPtr->State == VAR_ADDED) { if ((AtRuntime () && ((Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)) == 0) { + + // + // Don't return NV variable when HOB overrides it + // + if ((VariableStoreHeader[VariableStoreTypeHob] != NULL) && (VariableStoreHeader[VariableStoreTypeNv] != NULL) && + (Variable.StartPtr == GetStartPointer (VariableStoreHeader[VariableStoreTypeNv])) + ) { + VariableInHob.StartPtr = GetStartPointer (VariableStoreHeader[VariableStoreTypeHob]); + VariableInHob.EndPtr = GetEndPointer (VariableStoreHeader[VariableStoreTypeHob]); + Status = FindVariableEx ( + GetVariableNamePtr (Variable.CurrPtr), + &Variable.CurrPtr->VendorGuid, + &VariableInHob + ); + if (!EFI_ERROR (Status)) { + Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr); + continue; + } + } + VarNameSize = NameSizeOfVariable (Variable.CurrPtr); ASSERT (VarNameSize != 0); if (VarNameSize <= *VariableNameSize) { - CopyMem ( - VariableName, - GetVariableNamePtr (Variable.CurrPtr), - VarNameSize - ); - CopyMem ( - VendorGuid, - &Variable.CurrPtr->VendorGuid, - sizeof (EFI_GUID) - ); + CopyMem (VariableName, GetVariableNamePtr (Variable.CurrPtr), VarNameSize); + CopyMem (VendorGuid, &Variable.CurrPtr->VendorGuid, sizeof (EFI_GUID)); Status = EFI_SUCCESS; } else { Status = EFI_BUFFER_TOO_SMALL; @@ -2376,16 +2431,16 @@ VariableWriteServiceInitialize ( UINTN Index; UINT8 Data; EFI_PHYSICAL_ADDRESS VariableStoreBase; - UINT64 VariableStoreLength; + VARIABLE_HEADER *Variable; + VOID *VariableData; VariableStoreBase = mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase; VariableStoreHeader = (VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase; - VariableStoreLength = VariableStoreHeader->Size; - + // // Check if the free area is really free. // - for (Index = mVariableModuleGlobal->NonVolatileLastVariableOffset; Index < VariableStoreLength; Index++) { + for (Index = mVariableModuleGlobal->NonVolatileLastVariableOffset; Index < VariableStoreHeader->Size; Index++) { Data = ((UINT8 *) mNvVariableCache)[Index]; if (Data != 0xff) { // @@ -2404,6 +2459,35 @@ VariableWriteServiceInitialize ( } } + + // + // Flush the HOB variable to flash and invalidate HOB variable. + // + if (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0) { + // + // Clear the HobVariableBase to avoid SetVariable() updating the variable in HOB + // + VariableStoreHeader = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase; + mVariableModuleGlobal->VariableGlobal.HobVariableBase = 0; + + for ( Variable = GetStartPointer (VariableStoreHeader) + ; (Variable < GetEndPointer (VariableStoreHeader) && IsValidVariableHeader (Variable)) + ; Variable = GetNextVariablePtr (Variable) + ) { + ASSERT (Variable->State == VAR_ADDED); + ASSERT ((Variable->Attributes & EFI_VARIABLE_NON_VOLATILE) != 0); + VariableData = GetVariableDataPtr (Variable); + Status = VariableServiceSetVariable ( + GetVariableNamePtr (Variable), + &Variable->VendorGuid, + Variable->Attributes, + Variable->DataSize, + VariableData + ); + ASSERT_EFI_ERROR (Status); + } + } + // // Authenticated variable initialize. // @@ -2434,6 +2518,7 @@ VariableCommonInitialize ( UINT64 VariableStoreLength; UINTN ScratchSize; UINTN VariableSize; + EFI_HOB_GUID_TYPE *GuidHob; // // Allocate runtime memory for variable driver global structure. @@ -2453,6 +2538,19 @@ VariableCommonInitialize ( // ASSERT (PcdGet32 (PcdHwErrStorageSize) <= PcdGet32 (PcdFlashNvStorageVariableSize)); + // + // Get HOB variable store. + // + GuidHob = GetFirstGuidHob (&gEfiAuthenticatedVariableGuid); + if (GuidHob != NULL) { + VariableStoreHeader = GET_GUID_HOB_DATA (GuidHob); + if (GetVariableStoreStatus (VariableStoreHeader) == EfiValid) { + mVariableModuleGlobal->VariableGlobal.HobVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VariableStoreHeader; + } else { + DEBUG ((EFI_D_ERROR, "HOB Variable Store header is corrupted!\n")); + } + } + // // Allocate memory for volatile variable store, note that there is a scratch space to store scratch data. // @@ -2480,7 +2578,7 @@ VariableCommonInitialize ( VolatileVariableStore->Reserved1 = 0; // - // Get non-volatile varaible store. + // Get non-volatile variable store. // TempVariableStoreHeader = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageVariableBase64); diff --git a/SecurityPkg/VariableAuthenticated/RuntimeDxe/Variable.h b/SecurityPkg/VariableAuthenticated/RuntimeDxe/Variable.h index 6865f0dc71..91c7b4aac0 100644 --- a/SecurityPkg/VariableAuthenticated/RuntimeDxe/Variable.h +++ b/SecurityPkg/VariableAuthenticated/RuntimeDxe/Variable.h @@ -22,6 +22,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include #include #include +#include #include #include #include @@ -46,6 +47,13 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. /// #define ISO_639_2_ENTRY_SIZE 3 +typedef enum { + VariableStoreTypeVolatile, + VariableStoreTypeHob, + VariableStoreTypeNv, + VariableStoreTypeMax +} VARIABLE_STORE_TYPE; + typedef struct { VARIABLE_HEADER *CurrPtr; VARIABLE_HEADER *EndPtr; @@ -54,6 +62,7 @@ typedef struct { } VARIABLE_POINTER_TRACK; typedef struct { + EFI_PHYSICAL_ADDRESS HobVariableBase; EFI_PHYSICAL_ADDRESS VolatileVariableBase; EFI_PHYSICAL_ADDRESS NonVolatileVariableBase; EFI_LOCK VariableServicesLock; diff --git a/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableRuntimeDxe.inf b/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableRuntimeDxe.inf index 785808419d..5b2689efdb 100644 --- a/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableRuntimeDxe.inf +++ b/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableRuntimeDxe.inf @@ -54,7 +54,8 @@ UefiDriverEntryPoint PcdLib BaseCryptLib - PlatformSecureLib + PlatformSecureLib + HobLib [Protocols] gEfiFirmwareVolumeBlockProtocolGuid ## SOMETIMES_CONSUMES diff --git a/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmm.inf b/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmm.inf index 63c34e4cf5..01bda726d0 100644 --- a/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmm.inf +++ b/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmm.inf @@ -61,6 +61,7 @@ DxeServicesTableLib BaseCryptLib PlatformSecureLib + HobLib [Protocols] gEfiSmmFirmwareVolumeBlockProtocolGuid ## SOMETIMES_CONSUMES