/** @file Copyright (c) 2017, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include #include #include #include #include #include #include #include "Variable.h" #include "Fce.h" /** Gets the pointer to the first variable header in given variable store area. @param VarStoreHeader Pointer to the Variable Store Header. @return Pointer to the first variable header **/ STATIC AUTHENTICATED_VARIABLE_HEADER * GetStartPointer ( IN VARIABLE_STORE_HEADER *VarStoreHeader ) { // // The end of variable store // return (AUTHENTICATED_VARIABLE_HEADER *) HEADER_ALIGN (VarStoreHeader + 1); } /** This code gets the pointer to the last variable memory pointer byte. @param VarStoreHeader Pointer to the Variable Store Header. @return AUTHENTICATED_VARIABLE_HEADER* pointer to last unavailable Variable Header. **/ STATIC AUTHENTICATED_VARIABLE_HEADER * GetEndPointer ( IN VARIABLE_STORE_HEADER *VarStoreHeader ) { // // The end of variable store // return (AUTHENTICATED_VARIABLE_HEADER *) HEADER_ALIGN ((UINTN) VarStoreHeader + VarStoreHeader->Size); } /** This code checks if variable header is valid or not. @param Variable Pointer to the Variable Header. @retval TRUE Variable header is valid. @retval FALSE Variable header is not valid. **/ STATIC BOOLEAN IsValidVariableHeader ( IN AUTHENTICATED_VARIABLE_HEADER *Variable ) { if (Variable == NULL || Variable->StartId != VARIABLE_DATA ) { return FALSE; } return TRUE; } /** This code gets the size of name of variable. @param Variable Pointer to the Variable Header. @return Size of variable in bytes in type UINTN. **/ STATIC UINTN NameSizeOfVariable ( IN AUTHENTICATED_VARIABLE_HEADER *Variable ) { if (Variable->State == (UINT8) (-1) || Variable->DataSize == (UINT32) (-1) || Variable->NameSize == (UINT32) (-1) || Variable->Attributes == (UINT32) (-1)) { return 0; } return (UINTN) Variable->NameSize; } /** This code gets the size of data of variable. @param Variable Pointer to the Variable Header. @return Size of variable in bytes in type UINTN. **/ STATIC UINTN DataSizeOfVariable ( IN AUTHENTICATED_VARIABLE_HEADER *Variable ) { if (Variable->State == (UINT8) (-1) || Variable->DataSize == (UINT32) (-1) || Variable->NameSize == (UINT32) (-1) || Variable->Attributes == (UINT32) (-1)) { return 0; } return (UINTN) Variable->DataSize; } /** This code gets the pointer to the variable name. @param Variable Pointer to the Variable Header. @return A CHAR16* pointer to Variable Name. **/ STATIC CHAR16 * GetVariableNamePtr ( IN AUTHENTICATED_VARIABLE_HEADER *Variable ) { return (CHAR16 *) (Variable + 1); } /** This code gets the pointer to the variable data. @param Variable Pointer to the Variable Header. @return A UINT8* pointer to Variable Data. **/ STATIC UINT8 * GetVariableDataPtr ( IN AUTHENTICATED_VARIABLE_HEADER *Variable ) { UINTN Value; // // Be careful about pad size for alignment // Value = (UINTN) GetVariableNamePtr (Variable); Value += NameSizeOfVariable (Variable); Value += GET_PAD_SIZE (NameSizeOfVariable (Variable)); return (UINT8 *) Value; } /** This code gets the pointer to the next variable header. @param Variable Pointer to the Variable Header. @return A AUTHENTICATED_VARIABLE_HEADER* pointer to next variable header. **/ STATIC AUTHENTICATED_VARIABLE_HEADER * GetNextVariablePtr ( IN AUTHENTICATED_VARIABLE_HEADER *Variable ) { UINTN Value; if (!IsValidVariableHeader (Variable)) { return NULL; } Value = (UINTN) GetVariableDataPtr (Variable); Value += DataSizeOfVariable (Variable); Value += GET_PAD_SIZE (DataSizeOfVariable (Variable)); // // Be careful about pad size for alignment // return (AUTHENTICATED_VARIABLE_HEADER *) HEADER_ALIGN (Value); } EFI_STATUS EFIAPI BuildDefaultDataHobForRecoveryVariable ( IN EFI_PEI_SERVICES **PeiServices, IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, IN VOID *Ppi ) /*++ Routine Description: Convert Authenticated variable to normal variable data. Arguments: PeiServices General purpose services available to every PEIM. NotifyDescriptor Notify that this module published. Ppi PPI that was installed. Returns: EFI_SUCCESS The function completed successfully. --*/ { EFI_HOB_GUID_TYPE *GuidHob; VARIABLE_STORE_HEADER *AuthVarStoreHeader; VARIABLE_STORE_HEADER *VarStoreHeader; UINT32 VarStoreSize; AUTHENTICATED_VARIABLE_HEADER *AuthStartPtr; AUTHENTICATED_VARIABLE_HEADER *AuthEndPtr; AUTHENTICATED_VARIABLE_HEADER *AuthVariable; VARIABLE_HEADER *Variable; UINT8 *AuthVariablePtr; UINT8 *VariablePtr; GuidHob = GetFirstGuidHob (&gEfiAuthenticatedVariableGuid); AuthVarStoreHeader = (VARIABLE_STORE_HEADER *) GET_GUID_HOB_DATA (GuidHob); // // Go through AuthVarStore to calculate the required size for normal varstore. // VarStoreSize = sizeof (VARIABLE_STORE_HEADER); AuthStartPtr = GetStartPointer (AuthVarStoreHeader); AuthEndPtr = GetEndPointer (AuthVarStoreHeader); AuthVariable = AuthStartPtr; while ((AuthVariable < AuthEndPtr) && IsValidVariableHeader (AuthVariable)) { if (AuthVariable->State == VAR_ADDED) { VarStoreSize = HEADER_ALIGN (VarStoreSize); VarStoreSize += sizeof (VARIABLE_HEADER); VarStoreSize += AuthVariable->NameSize + GET_PAD_SIZE (AuthVariable->NameSize); VarStoreSize += AuthVariable->DataSize + GET_PAD_SIZE (AuthVariable->DataSize); } AuthVariable = GetNextVariablePtr (AuthVariable); } // // Create HOB data for normal variable storage. // Allocate more data for header alignment. // VarStoreSize = VarStoreSize + HEADER_ALIGNMENT - 1; VarStoreHeader = (VARIABLE_STORE_HEADER *) BuildGuidHob (&gEfiVariableGuid, VarStoreSize); ASSERT (VarStoreHeader != NULL); CopyGuid (&VarStoreHeader->Signature, &gEfiVariableGuid); VarStoreHeader->Format = AuthVarStoreHeader->Format; VarStoreHeader->State = AuthVarStoreHeader->State; // // Copy variable data from AuthVarStore to NormalVarStore // AuthVariable = AuthStartPtr; VariablePtr = (UINT8 *) (VarStoreHeader + 1); while ((AuthVariable < AuthEndPtr) && IsValidVariableHeader (AuthVariable)) { if (AuthVariable->State == VAR_ADDED) { Variable = (VARIABLE_HEADER *) HEADER_ALIGN ((UINTN) VariablePtr); // // Copy variable header // Variable->StartId = AuthVariable->StartId; Variable->State = AuthVariable->State; Variable->Reserved = AuthVariable->Reserved; Variable->Attributes = AuthVariable->Attributes; Variable->NameSize = AuthVariable->NameSize; Variable->DataSize = AuthVariable->DataSize; CopyGuid (&Variable->VendorGuid, &AuthVariable->VendorGuid); // // Copy variable Name and Data // VariablePtr = (UINT8 *) (Variable + 1); AuthVariablePtr = (UINT8 *) (AuthVariable + 1); CopyMem (VariablePtr, AuthVariablePtr, Variable->NameSize); VariablePtr = VariablePtr + Variable->NameSize + GET_PAD_SIZE (Variable->NameSize); AuthVariablePtr = AuthVariablePtr + AuthVariable->NameSize + GET_PAD_SIZE (AuthVariable->NameSize); CopyMem (VariablePtr, AuthVariablePtr, Variable->DataSize); VariablePtr = VariablePtr + Variable->DataSize + GET_PAD_SIZE (Variable->DataSize); } AuthVariable = GetNextVariablePtr (AuthVariable); } // // Update Variable Storage Size // VarStoreHeader->Size = (UINT32) ((UINTN) VariablePtr - (UINTN) VarStoreHeader); return EFI_SUCCESS; } static EFI_PEI_NOTIFY_DESCRIPTOR mMemoryNotifyList = { (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), &gEfiPeiMemoryDiscoveredPpiGuid, BuildDefaultDataHobForRecoveryVariable }; /** This function finds the matched default data and create GUID hob for it. @param StoreId Specifies the type of defaults to retrieve. @param SkuId Specifies the platform board of defaults to retrieve. @retval EFI_SUCCESS The matched default data is found. @retval EFI_NOT_FOUND The matched default data is not found. @retval EFI_OUT_OF_RESOURCES No enough resource to create HOB. **/ EFI_STATUS EFIAPI CreateDefaultVariableHob ( IN UINT16 StoreId, IN UINT16 SkuId ) { UINTN FvInstance; EFI_FIRMWARE_VOLUME_HEADER *FvHeader; EFI_FFS_FILE_HEADER *FfsHeader; UINT32 FileSize; EFI_COMMON_SECTION_HEADER *Section; UINT32 SectionLength; EFI_STATUS Status; BOOLEAN DefaultFileIsFound; DEFAULT_DATA *DefaultData; DEFAULT_INFO *DefaultInfo; VARIABLE_STORE_HEADER *VarStoreHeader; VARIABLE_STORE_HEADER *VarStoreHeaderHob; UINT8 *VarHobPtr; UINT8 *VarPtr; UINT32 VarDataOffset; UINT32 VarHobDataOffset; EFI_BOOT_MODE BootMode; CONST EFI_PEI_SERVICES **PeiServices; // // Get PeiService pointer // PeiServices = GetPeiServicesTablePointer (); // // Find the FFS file that stores all default data. // DefaultFileIsFound = FALSE; FvInstance = 0; FfsHeader = NULL; while (((*PeiServices)->FfsFindNextVolume (PeiServices, FvInstance, (VOID **)&FvHeader) == EFI_SUCCESS) && (!DefaultFileIsFound)) { FfsHeader = NULL; while ((*PeiServices)->FfsFindNextFile (PeiServices, EFI_FV_FILETYPE_FREEFORM, FvHeader, (VOID **)&FfsHeader) == EFI_SUCCESS) { if (CompareGuid ((EFI_GUID *) FfsHeader, &gDefaultDataFileGuid)) { DefaultFileIsFound = TRUE; break; } } FvInstance ++; } // // FFS file is not found. // if (!DefaultFileIsFound) { return EFI_NOT_FOUND; } // // Find the matched default data for the input default ID and plat ID. // VarStoreHeader = NULL; Section = (EFI_COMMON_SECTION_HEADER *)(FfsHeader + 1); FileSize = *(UINT32 *)(FfsHeader->Size) & 0x00FFFFFF; while (((UINTN) Section < (UINTN) FfsHeader + FileSize) && (VarStoreHeader == NULL)) { DefaultData = (DEFAULT_DATA *) (Section + 1); DefaultInfo = &(DefaultData->DefaultInfo[0]); while ((UINTN) DefaultInfo < (UINTN) DefaultData + DefaultData->HeaderSize) { if (DefaultInfo->DefaultId == StoreId && DefaultInfo->BoardId == SkuId) { VarStoreHeader = (VARIABLE_STORE_HEADER *) ((UINT8 *) DefaultData + DefaultData->HeaderSize); break; } DefaultInfo ++; } // // Size is 24 bits wide so mask upper 8 bits. // SectionLength is adjusted it is 4 byte aligned. // Go to the next section // SectionLength = *(UINT32 *)Section->Size & 0x00FFFFFF; SectionLength = (SectionLength + 3) & (~3); ASSERT (SectionLength != 0); Section = (EFI_COMMON_SECTION_HEADER *)((UINT8 *)Section + SectionLength); } // // Matched default data is not found. // if (VarStoreHeader == NULL) { return EFI_NOT_FOUND; } // // Create HOB to store default data so that Variable driver can use it. // Allocate more data for header alignment. // VarStoreHeaderHob = (VARIABLE_STORE_HEADER *) BuildGuidHob (&VarStoreHeader->Signature, VarStoreHeader->Size + HEADER_ALIGNMENT - 1); if (VarStoreHeaderHob == NULL) { // // No enough hob resource. // return EFI_OUT_OF_RESOURCES; } // // Copy variable storage header. // CopyMem (VarStoreHeaderHob, VarStoreHeader, sizeof (VARIABLE_STORE_HEADER)); // // Copy variable data. // VarPtr = (UINT8 *) HEADER_ALIGN ((UINTN) (VarStoreHeader + 1)); VarDataOffset = (UINT32) ((UINTN) VarPtr - (UINTN) VarStoreHeader); VarHobPtr = (UINT8 *) HEADER_ALIGN ((UINTN) (VarStoreHeaderHob + 1)); VarHobDataOffset = (UINT32) ((UINTN) VarHobPtr - (UINTN) VarStoreHeaderHob); CopyMem (VarHobPtr, VarPtr, VarStoreHeader->Size - VarDataOffset); // // Update variable size. // VarStoreHeaderHob->Size = VarStoreHeader->Size - VarDataOffset + VarHobDataOffset; // // On recovery boot mode, emulation variable driver will be used. // But, Emulation variable only knows normal variable data format. // So, if the default variable data format is authenticated, it needs to be converted to normal data. // Status = (*PeiServices)->GetBootMode (PeiServices, &BootMode); if (BootMode == BOOT_IN_RECOVERY_MODE && CompareGuid (&VarStoreHeader->Signature, &gEfiAuthenticatedVariableGuid)) { Status = (**PeiServices).NotifyPpi (PeiServices, &mMemoryNotifyList); ASSERT_EFI_ERROR (Status); } return EFI_SUCCESS; }