/** @file Copyright (c) 2017, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License that accompanies this distribution. The full text of the license may be found at http://opensource.org/licenses/bsd-license.php. THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. **/ #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; }