/** Gets firmware volume block handle by given address. This function gets firmware volume block handle whose address range contains the parameter Address. @param[in] Address Address which should be contained by returned FVB handle. @param[out] FvbHandle Pointer to FVB handle for output. @retval EFI_SUCCESS FVB handle successfully returned. @retval EFI_NOT_FOUND Failed to find FVB handle by address. **/ EFI_STATUS GetFvbHandleByAddress ( IN EFI_PHYSICAL_ADDRESS Address, OUT EFI_HANDLE *FvbHandle ) { EFI_STATUS Status; EFI_HANDLE *HandleBuffer; UINTN HandleCount; UINTN Index; EFI_PHYSICAL_ADDRESS FvbBaseAddress; EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb; EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; *FvbHandle = NULL; // // Locate all handles with Firmware Volume Block protocol // Status = gBS->LocateHandleBuffer ( ByProtocol, &gEfiFirmwareVolumeBlockProtocolGuid, NULL, &HandleCount, &HandleBuffer ); if (EFI_ERROR (Status)) { return EFI_NOT_FOUND; } // // Traverse all the handles, searching for the one containing parameter Address // for (Index = 0; Index < HandleCount; Index += 1) { Status = gBS->HandleProtocol ( HandleBuffer[Index], &gEfiFirmwareVolumeBlockProtocolGuid, (VOID **) &Fvb ); if (EFI_ERROR (Status)) { Status = EFI_NOT_FOUND; break; } // // Checks if the address range of this handle contains parameter Address // Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress); if (EFI_ERROR (Status)) { continue; } FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress); if ((Address >= FvbBaseAddress) && (Address <= (FvbBaseAddress + FwVolHeader->FvLength))) { *FvbHandle = HandleBuffer[Index]; Status = EFI_SUCCESS; break; } } FreePool (HandleBuffer); return Status; }
EFI_STATUS GetFvbHandleByAddress ( IN EFI_PHYSICAL_ADDRESS Address, OUT EFI_HANDLE *FvbHandle ) { EFI_STATUS Status; EFI_HANDLE *HandleBuffer; UINTN HandleCount; UINTN Index; EFI_PHYSICAL_ADDRESS FvbBaseAddress; EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb; EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; *FvbHandle = NULL; // // Locate all handles of Fvb protocol // Status = gBS->LocateHandleBuffer ( ByProtocol, &gEfiFirmwareVolumeBlockProtocolGuid, NULL, &HandleCount, &HandleBuffer ); if (EFI_ERROR (Status)) { return EFI_NOT_FOUND; } // // Get the FVB to access variable store // for (Index = 0; Index < HandleCount; Index += 1) { Status = gBS->HandleProtocol ( HandleBuffer[Index], &gEfiFirmwareVolumeBlockProtocolGuid, (VOID **) &Fvb ); if (EFI_ERROR (Status)) { Status = EFI_NOT_FOUND; break; } // // Compare the address and select the right one // Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress); if (EFI_ERROR (Status)) { continue; } FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress); if ((Address >= FvbBaseAddress) && (Address <= (FvbBaseAddress + FwVolHeader->FvLength))) { *FvbHandle = HandleBuffer[Index]; Status = EFI_SUCCESS; break; } } gBS->FreePool (HandleBuffer); return Status; }
/** Gets LBA of block and offset by given address. This function gets the Logical Block Address (LBA) of a firmware volume block containing the given address, and the offset of the address on the block. @param Address Address which should be contained by returned FVB handle. @param Lba Pointer to LBA for output. @param Offset Pointer to offset for output. @retval EFI_SUCCESS LBA and offset successfully returned. @retval EFI_NOT_FOUND Fail to find FVB handle by address. @retval EFI_ABORTED Fail to find valid LBA and offset. **/ EFI_STATUS GetLbaAndOffsetByAddress ( IN EFI_PHYSICAL_ADDRESS Address, OUT EFI_LBA *Lba, OUT UINTN *Offset ) { EFI_STATUS Status; EFI_PHYSICAL_ADDRESS FvbBaseAddress; EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb; EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; EFI_FV_BLOCK_MAP_ENTRY *FvbMapEntry; UINT32 LbaIndex; *Lba = (EFI_LBA) (-1); *Offset = 0; // // Get the proper FVB protocol. // Status = GetFvbInfoByAddress (Address, NULL, &Fvb); if (EFI_ERROR (Status)) { return Status; } // // Get the Base Address of FV. // Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress); if (EFI_ERROR (Status)) { return Status; } FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress); // // Get the (LBA, Offset) of Address. // if ((FwVolHeader->FvLength) > (FwVolHeader->HeaderLength)) { // // BUGBUG: Assume one FV has one type of BlockLength. // FvbMapEntry = &FwVolHeader->BlockMap[0]; for (LbaIndex = 1; LbaIndex <= FvbMapEntry->NumBlocks; LbaIndex += 1) { if (Address < (FvbBaseAddress + FvbMapEntry->Length * LbaIndex)) { // // Found the (Lba, Offset). // *Lba = LbaIndex - 1; *Offset = (UINTN) (Address - (FvbBaseAddress + FvbMapEntry->Length * (LbaIndex - 1))); return EFI_SUCCESS; } } } return EFI_ABORTED; }
/** Get firmware block by address. @param Address Address specified the block @param FvBlock The block caller wanted @retval EFI_SUCCESS The protocol instance if found. @retval EFI_NOT_FOUND Block not found **/ EFI_HANDLE GetFvbByAddress ( IN EFI_PHYSICAL_ADDRESS Address, OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvBlock ) { EFI_STATUS Status; EFI_HANDLE *HandleBuffer; UINTN HandleCount; UINTN Index; EFI_PHYSICAL_ADDRESS FvbBaseAddress; EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb; EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; EFI_HANDLE FvbHandle; *FvBlock = NULL; FvbHandle = NULL; HandleBuffer = NULL; // // Locate all handles of Fvb protocol // Status = GetFvbCountAndBuffer (&HandleCount, &HandleBuffer); if (EFI_ERROR (Status)) { return NULL; } // // Get the FVB to access variable store // for (Index = 0; Index < HandleCount; Index += 1) { Status = FtwGetFvbByHandle (HandleBuffer[Index], &Fvb); if (EFI_ERROR (Status)) { break; } // // Compare the address and select the right one // Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress); if (EFI_ERROR (Status)) { continue; } FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress); if ((Address >= FvbBaseAddress) && (Address <= (FvbBaseAddress + (FwVolHeader->FvLength - 1)))) { *FvBlock = Fvb; FvbHandle = HandleBuffer[Index]; break; } } FreePool (HandleBuffer); return FvbHandle; }
/** Get the FvbBaseAddress and FvbAttributes from the FVB handle FvbHandle. @param[in] FvbHandle The handle of FVB protocol that provides services. @param[out] FvbBaseAddress The base address of the FVB attached with FvbHandle. @param[out] FvbAttributes The attributes of the FVB attached with FvbHandle. @retval EFI_SUCCESS The function completed successfully. @retval Others The function could not complete successfully. **/ EFI_STATUS ConvertFvbHandle ( IN EFI_HANDLE FvbHandle, OUT EFI_PHYSICAL_ADDRESS *FvbBaseAddress, OUT EFI_FVB_ATTRIBUTES_2 *FvbAttributes ) { EFI_STATUS Status; EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb; Status = gBS->HandleProtocol (FvbHandle, &gEfiFirmwareVolumeBlockProtocolGuid, (VOID **) &Fvb); if (EFI_ERROR (Status)) { return Status; } Status = Fvb->GetPhysicalAddress (Fvb, FvbBaseAddress); if (EFI_ERROR (Status)) { return Status; } Status = Fvb->GetAttributes (Fvb, FvbAttributes); return Status; }
/** Check if an FV is consistent and allocate cache for it. @param FvDevice A pointer to the FvDevice to be checked. @retval EFI_OUT_OF_RESOURCES No enough buffer could be allocated. @retval EFI_SUCCESS FV is consistent and cache is allocated. @retval EFI_VOLUME_CORRUPTED File system is corrupted. **/ EFI_STATUS FvCheck ( IN OUT FV_DEVICE *FvDevice ) { EFI_STATUS Status; EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb; EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; EFI_FIRMWARE_VOLUME_EXT_HEADER *FwVolExtHeader; EFI_FVB_ATTRIBUTES_2 FvbAttributes; EFI_FV_BLOCK_MAP_ENTRY *BlockMap; FFS_FILE_LIST_ENTRY *FfsFileEntry; EFI_FFS_FILE_HEADER *FfsHeader; UINT8 *CacheLocation; UINTN LbaOffset; UINTN HeaderSize; UINTN Index; EFI_LBA LbaIndex; UINTN Size; EFI_FFS_FILE_STATE FileState; UINT8 *TopFvAddress; UINTN TestLength; EFI_PHYSICAL_ADDRESS PhysicalAddress; BOOLEAN FileCached; UINTN WholeFileSize; EFI_FFS_FILE_HEADER *CacheFfsHeader; FileCached = FALSE; CacheFfsHeader = NULL; Fvb = FvDevice->Fvb; FwVolHeader = FvDevice->FwVolHeader; Status = Fvb->GetAttributes (Fvb, &FvbAttributes); if (EFI_ERROR (Status)) { return Status; } // // Size is the size of the FV minus the head. We have already allocated // the header to check to make sure the volume is valid // Size = (UINTN)(FwVolHeader->FvLength - FwVolHeader->HeaderLength); if ((FvbAttributes & EFI_FVB2_MEMORY_MAPPED) != 0) { FvDevice->IsMemoryMapped = TRUE; Status = Fvb->GetPhysicalAddress (Fvb, &PhysicalAddress); if (EFI_ERROR (Status)) { return Status; } // // Don't cache memory mapped FV really. // FvDevice->CachedFv = (UINT8 *) (UINTN) (PhysicalAddress + FwVolHeader->HeaderLength); } else { FvDevice->IsMemoryMapped = FALSE; FvDevice->CachedFv = AllocatePool (Size); if (FvDevice->CachedFv == NULL) { return EFI_OUT_OF_RESOURCES; } } // // Remember a pointer to the end fo the CachedFv // FvDevice->EndOfCachedFv = FvDevice->CachedFv + Size; if (!FvDevice->IsMemoryMapped) { // // Copy FV minus header into memory using the block map we have all ready // read into memory. // BlockMap = FwVolHeader->BlockMap; CacheLocation = FvDevice->CachedFv; LbaIndex = 0; LbaOffset = 0; HeaderSize = FwVolHeader->HeaderLength; while ((BlockMap->NumBlocks != 0) || (BlockMap->Length != 0)) { Index = 0; Size = BlockMap->Length; if (HeaderSize > 0) { // // Skip header size // for (; Index < BlockMap->NumBlocks && HeaderSize >= BlockMap->Length; Index ++) { HeaderSize -= BlockMap->Length; LbaIndex ++; } // // Check whether FvHeader is crossing the multi block range. // if (Index >= BlockMap->NumBlocks) { BlockMap++; continue; } else if (HeaderSize > 0) { LbaOffset = HeaderSize; Size = BlockMap->Length - HeaderSize; HeaderSize = 0; } } // // read the FV data // for (; Index < BlockMap->NumBlocks; Index ++) { Status = Fvb->Read (Fvb, LbaIndex, LbaOffset, &Size, CacheLocation ); // // Not check EFI_BAD_BUFFER_SIZE, for Size = BlockMap->Length // if (EFI_ERROR (Status)) { goto Done; } LbaIndex++; CacheLocation += Size; // // After we skip Fv Header always read from start of block // LbaOffset = 0; Size = BlockMap->Length; } BlockMap++; } } // // Scan to check the free space & File list // if ((FvbAttributes & EFI_FVB2_ERASE_POLARITY) != 0) { FvDevice->ErasePolarity = 1; } else { FvDevice->ErasePolarity = 0; } // // go through the whole FV cache, check the consistence of the FV. // Make a linked list of all the Ffs file headers // Status = EFI_SUCCESS; InitializeListHead (&FvDevice->FfsFileListHeader); // // Build FFS list // if (FwVolHeader->ExtHeaderOffset != 0) { // // Searching for files starts on an 8 byte aligned boundary after the end of the Extended Header if it exists. // FwVolExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *) (FvDevice->CachedFv + (FwVolHeader->ExtHeaderOffset - FwVolHeader->HeaderLength)); FfsHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FwVolExtHeader + FwVolExtHeader->ExtHeaderSize); FfsHeader = (EFI_FFS_FILE_HEADER *) ALIGN_POINTER (FfsHeader, 8); } else { FfsHeader = (EFI_FFS_FILE_HEADER *) (FvDevice->CachedFv); } TopFvAddress = FvDevice->EndOfCachedFv; while (((UINTN) FfsHeader >= (UINTN) FvDevice->CachedFv) && ((UINTN) FfsHeader <= (UINTN) ((UINTN) TopFvAddress - sizeof (EFI_FFS_FILE_HEADER)))) { if (FileCached) { CoreFreePool (CacheFfsHeader); FileCached = FALSE; } TestLength = TopFvAddress - ((UINT8 *) FfsHeader); if (TestLength > sizeof (EFI_FFS_FILE_HEADER)) { TestLength = sizeof (EFI_FFS_FILE_HEADER); } if (IsBufferErased (FvDevice->ErasePolarity, FfsHeader, TestLength)) { // // We have found the free space so we are done! // goto Done; } if (!IsValidFfsHeader (FvDevice->ErasePolarity, FfsHeader, &FileState)) { if ((FileState == EFI_FILE_HEADER_INVALID) || (FileState == EFI_FILE_HEADER_CONSTRUCTION)) { if (IS_FFS_FILE2 (FfsHeader)) { if (!FvDevice->IsFfs3Fv) { DEBUG ((EFI_D_ERROR, "Found a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &FfsHeader->Name)); } FfsHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsHeader + sizeof (EFI_FFS_FILE_HEADER2)); } else { FfsHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsHeader + sizeof (EFI_FFS_FILE_HEADER)); } continue; } else { // // File system is corrputed // Status = EFI_VOLUME_CORRUPTED; goto Done; } } CacheFfsHeader = FfsHeader; if ((CacheFfsHeader->Attributes & FFS_ATTRIB_CHECKSUM) == FFS_ATTRIB_CHECKSUM) { if (FvDevice->IsMemoryMapped) { // // Memory mapped FV has not been cached. // Here is to cache FFS file to memory buffer for following checksum calculating. // And then, the cached file buffer can be also used for FvReadFile. // WholeFileSize = IS_FFS_FILE2 (CacheFfsHeader) ? FFS_FILE2_SIZE (CacheFfsHeader): FFS_FILE_SIZE (CacheFfsHeader); CacheFfsHeader = AllocateCopyPool (WholeFileSize, CacheFfsHeader); if (CacheFfsHeader == NULL) { Status = EFI_OUT_OF_RESOURCES; goto Done; } FileCached = TRUE; } } if (!IsValidFfsFile (FvDevice->ErasePolarity, CacheFfsHeader)) { // // File system is corrupted // Status = EFI_VOLUME_CORRUPTED; goto Done; } if (IS_FFS_FILE2 (CacheFfsHeader)) { ASSERT (FFS_FILE2_SIZE (CacheFfsHeader) > 0x00FFFFFF); if (!FvDevice->IsFfs3Fv) { DEBUG ((EFI_D_ERROR, "Found a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &CacheFfsHeader->Name)); FfsHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsHeader + FFS_FILE2_SIZE (CacheFfsHeader)); // // Adjust pointer to the next 8-byte aligned boundry. // FfsHeader = (EFI_FFS_FILE_HEADER *) (((UINTN) FfsHeader + 7) & ~0x07); continue; } } FileState = GetFileState (FvDevice->ErasePolarity, CacheFfsHeader); // // check for non-deleted file // if (FileState != EFI_FILE_DELETED) { // // Create a FFS list entry for each non-deleted file // FfsFileEntry = AllocateZeroPool (sizeof (FFS_FILE_LIST_ENTRY)); if (FfsFileEntry == NULL) { Status = EFI_OUT_OF_RESOURCES; goto Done; } FfsFileEntry->FfsHeader = CacheFfsHeader; FfsFileEntry->FileCached = FileCached; FileCached = FALSE; InsertTailList (&FvDevice->FfsFileListHeader, &FfsFileEntry->Link); } if (IS_FFS_FILE2 (CacheFfsHeader)) { FfsHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsHeader + FFS_FILE2_SIZE (CacheFfsHeader)); } else { FfsHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsHeader + FFS_FILE_SIZE (CacheFfsHeader)); } // // Adjust pointer to the next 8-byte aligned boundry. // FfsHeader = (EFI_FFS_FILE_HEADER *)(((UINTN)FfsHeader + 7) & ~0x07); } Done: if (EFI_ERROR (Status)) { if (FileCached) { CoreFreePool (CacheFfsHeader); FileCached = FALSE; } FreeFvDeviceResource (FvDevice); } return Status; }
/** Find the proper Firmware Volume Block protocol for FTW operation. @param[in, out] FtwDevice Pointer to the FTW device structure @retval EFI_SUCCESS Find the FVB protocol successfully. @retval EFI_NOT_FOUND No proper FVB protocol was found. @retval EFI_ABORTED Some data can not be got or be invalid. **/ EFI_STATUS FindFvbForFtw ( IN OUT EFI_FTW_DEVICE *FtwDevice ) { EFI_STATUS Status; EFI_HANDLE *HandleBuffer; UINTN HandleCount; UINTN Index; EFI_PHYSICAL_ADDRESS FvbBaseAddress; EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb; EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; EFI_FVB_ATTRIBUTES_2 Attributes; EFI_FV_BLOCK_MAP_ENTRY *FvbMapEntry; UINT32 LbaIndex; // // Get all FVB handle. // Status = GetFvbCountAndBuffer (&HandleCount, &HandleBuffer); if (EFI_ERROR (Status)) { return EFI_NOT_FOUND; } // // Get the FVB to access variable store // Fvb = NULL; for (Index = 0; Index < HandleCount; Index += 1) { Status = FtwGetFvbByHandle (HandleBuffer[Index], &Fvb); if (EFI_ERROR (Status)) { Status = EFI_NOT_FOUND; break; } // // Ensure this FVB protocol support Write operation. // Status = Fvb->GetAttributes (Fvb, &Attributes); if (EFI_ERROR (Status) || ((Attributes & EFI_FVB2_WRITE_STATUS) == 0)) { continue; } // // Compare the address and select the right one // Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress); if (EFI_ERROR (Status)) { continue; } FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress); if ((FtwDevice->FtwFvBlock == NULL) && (FtwDevice->WorkSpaceAddress >= FvbBaseAddress) && ((FtwDevice->WorkSpaceAddress + FtwDevice->WorkSpaceLength) <= (FvbBaseAddress + FwVolHeader->FvLength)) ) { FtwDevice->FtwFvBlock = Fvb; // // To get the LBA of work space // if ((FwVolHeader->FvLength) > (FwVolHeader->HeaderLength)) { // // Now, one FV has one type of BlockLength // FvbMapEntry = &FwVolHeader->BlockMap[0]; for (LbaIndex = 1; LbaIndex <= FvbMapEntry->NumBlocks; LbaIndex += 1) { if ((FtwDevice->WorkSpaceAddress >= (FvbBaseAddress + FvbMapEntry->Length * (LbaIndex - 1))) && (FtwDevice->WorkSpaceAddress < (FvbBaseAddress + FvbMapEntry->Length * LbaIndex))) { FtwDevice->FtwWorkSpaceLba = LbaIndex - 1; // // Get the Work space size and Base(Offset) // FtwDevice->FtwWorkSpaceSize = FtwDevice->WorkSpaceLength; FtwDevice->FtwWorkSpaceBase = (UINTN) (FtwDevice->WorkSpaceAddress - (FvbBaseAddress + FvbMapEntry->Length * (LbaIndex - 1))); break; } } } } if ((FtwDevice->FtwBackupFvb == NULL) && (FtwDevice->SpareAreaAddress >= FvbBaseAddress) && ((FtwDevice->SpareAreaAddress + FtwDevice->SpareAreaLength) <= (FvbBaseAddress + FwVolHeader->FvLength)) ) { FtwDevice->FtwBackupFvb = Fvb; // // To get the LBA of spare // if ((FwVolHeader->FvLength) > (FwVolHeader->HeaderLength)) { // // Now, one FV has one type of BlockLength // FvbMapEntry = &FwVolHeader->BlockMap[0]; for (LbaIndex = 1; LbaIndex <= FvbMapEntry->NumBlocks; LbaIndex += 1) { if ((FtwDevice->SpareAreaAddress >= (FvbBaseAddress + FvbMapEntry->Length * (LbaIndex - 1))) && (FtwDevice->SpareAreaAddress < (FvbBaseAddress + FvbMapEntry->Length * LbaIndex))) { // // Get the NumberOfSpareBlock and BlockSize // FtwDevice->FtwSpareLba = LbaIndex - 1; FtwDevice->BlockSize = FvbMapEntry->Length; FtwDevice->NumberOfSpareBlock = FtwDevice->SpareAreaLength / FtwDevice->BlockSize; // // Check the range of spare area to make sure that it's in FV range // if ((FtwDevice->FtwSpareLba + FtwDevice->NumberOfSpareBlock) > FvbMapEntry->NumBlocks) { DEBUG ((EFI_D_ERROR, "Ftw: Spare area is out of FV range\n")); FreePool (HandleBuffer); ASSERT (FALSE); return EFI_ABORTED; } break; } } } } } FreePool (HandleBuffer); if ((FtwDevice->FtwBackupFvb == NULL) || (FtwDevice->FtwFvBlock == NULL) || (FtwDevice->FtwWorkSpaceLba == (EFI_LBA) (-1)) || (FtwDevice->FtwSpareLba == (EFI_LBA) (-1))) { return EFI_ABORTED; } return EFI_SUCCESS; }
/** Get the handle of the SMM FVB protocol by the FVB base address and attributes. @param[in] Address The base address of SMM FVB protocol. @param[in] Attributes The attributes of the SMM FVB protocol. @param[out] SmmFvbHandle The handle of the SMM FVB protocol. @retval EFI_SUCCESS The FVB handle is found. @retval EFI_ABORTED The FVB protocol is not found. **/ EFI_STATUS GetFvbByAddressAndAttribute ( IN EFI_PHYSICAL_ADDRESS Address, IN EFI_FVB_ATTRIBUTES_2 Attributes, OUT EFI_HANDLE *SmmFvbHandle ) { EFI_STATUS Status; EFI_HANDLE *HandleBuffer; UINTN HandleCount; UINTN Index; EFI_PHYSICAL_ADDRESS FvbBaseAddress; EFI_FVB_ATTRIBUTES_2 FvbAttributes; EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb; // // Locate all handles of SMM Fvb protocol. // Status = GetFvbCountAndBuffer (&HandleCount, &HandleBuffer); if (EFI_ERROR (Status)) { return EFI_ABORTED; } // // Find the proper SMM Fvb handle by the address and attributes. // for (Index = 0; Index < HandleCount; Index++) { Status = FtwGetFvbByHandle (HandleBuffer[Index], &Fvb); if (EFI_ERROR (Status)) { break; } // // Compare the address. // Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress); if (EFI_ERROR (Status)) { continue; } if (Address != FvbBaseAddress) { continue; } // // Compare the attribute. // Status = Fvb->GetAttributes (Fvb, &FvbAttributes); if (EFI_ERROR (Status)) { continue; } if (Attributes != FvbAttributes) { continue; } // // Found the proper FVB handle. // *SmmFvbHandle = HandleBuffer[Index]; FreePool (HandleBuffer); return EFI_SUCCESS; } FreePool (HandleBuffer); return EFI_ABORTED; }
/** Firmware Volume Block Protocol notification event handler. Initialization for Fault Tolerant Write is done in this handler. @param[in] Event Event whose notification function is being invoked. @param[in] Context Pointer to the notification function's context. **/ VOID EFIAPI FvbNotificationEvent ( IN EFI_EVENT Event, IN VOID *Context ) { EFI_STATUS Status; EFI_HANDLE *HandleBuffer; UINTN HandleCount; UINTN Index; EFI_PHYSICAL_ADDRESS FvbBaseAddress; EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb; EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; EFI_FVB_ATTRIBUTES_2 Attributes; EFI_FTW_DEVICE *FtwDevice; EFI_FV_BLOCK_MAP_ENTRY *FvbMapEntry; UINT32 LbaIndex; UINTN Length; EFI_FAULT_TOLERANT_WRITE_HEADER *FtwHeader; UINTN Offset; EFI_HANDLE FvbHandle; FtwDevice = (EFI_FTW_DEVICE *)Context; FvbHandle = NULL; Fvb = NULL; FtwDevice->WorkSpaceAddress = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageFtwWorkingBase); FtwDevice->SpareAreaAddress = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageFtwSpareBase); // // Locate all handles of Fvb protocol // Status = gBS->LocateHandleBuffer ( ByProtocol, &gEfiFirmwareVolumeBlockProtocolGuid, NULL, &HandleCount, &HandleBuffer ); if (EFI_ERROR (Status)) { return; } // // Get the FVB to access variable store // for (Index = 0; Index < HandleCount; Index += 1) { Status = gBS->HandleProtocol ( HandleBuffer[Index], &gEfiFirmwareVolumeBlockProtocolGuid, (VOID **) &Fvb ); if (EFI_ERROR (Status)) { Status = EFI_NOT_FOUND; break; } // // Ensure this FVB protocol supported Write operation. // Status = Fvb->GetAttributes (Fvb, &Attributes); if (EFI_ERROR (Status) || ((Attributes & EFI_FVB2_WRITE_STATUS) == 0)) { continue; } // // Compare the address and select the right one // Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress); if (EFI_ERROR (Status)) { continue; } FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress); if ((FtwDevice->FtwFvBlock == NULL) && (FtwDevice->WorkSpaceAddress >= FvbBaseAddress) && ((FtwDevice->WorkSpaceAddress + FtwDevice->WorkSpaceLength) <= (FvbBaseAddress + FwVolHeader->FvLength)) ) { FtwDevice->FtwFvBlock = Fvb; // // To get the LBA of work space // if ((FwVolHeader->FvLength) > (FwVolHeader->HeaderLength)) { // // Now, one FV has one type of BlockLength // FvbMapEntry = &FwVolHeader->BlockMap[0]; for (LbaIndex = 1; LbaIndex <= FvbMapEntry->NumBlocks; LbaIndex += 1) { if ((FtwDevice->WorkSpaceAddress >= (FvbBaseAddress + FvbMapEntry->Length * (LbaIndex - 1))) && (FtwDevice->WorkSpaceAddress < (FvbBaseAddress + FvbMapEntry->Length * LbaIndex))) { FtwDevice->FtwWorkSpaceLba = LbaIndex - 1; // // Get the Work space size and Base(Offset) // FtwDevice->FtwWorkSpaceSize = FtwDevice->WorkSpaceLength; FtwDevice->FtwWorkSpaceBase = (UINTN) (FtwDevice->WorkSpaceAddress - (FvbBaseAddress + FvbMapEntry->Length * (LbaIndex - 1))); break; } } } } if ((FtwDevice->FtwBackupFvb == NULL) && (FtwDevice->SpareAreaAddress >= FvbBaseAddress) && ((FtwDevice->SpareAreaAddress + FtwDevice->SpareAreaLength) <= (FvbBaseAddress + FwVolHeader->FvLength)) ) { FtwDevice->FtwBackupFvb = Fvb; // // To get the LBA of spare // if ((FwVolHeader->FvLength) > (FwVolHeader->HeaderLength)) { // // Now, one FV has one type of BlockLength // FvbMapEntry = &FwVolHeader->BlockMap[0]; for (LbaIndex = 1; LbaIndex <= FvbMapEntry->NumBlocks; LbaIndex += 1) { if ((FtwDevice->SpareAreaAddress >= (FvbBaseAddress + FvbMapEntry->Length * (LbaIndex - 1))) && (FtwDevice->SpareAreaAddress < (FvbBaseAddress + FvbMapEntry->Length * LbaIndex))) { // // Get the NumberOfSpareBlock and BlockSize // FtwDevice->FtwSpareLba = LbaIndex - 1; FtwDevice->BlockSize = FvbMapEntry->Length; FtwDevice->NumberOfSpareBlock = FtwDevice->SpareAreaLength / FtwDevice->BlockSize; // // Check the range of spare area to make sure that it's in FV range // if ((FtwDevice->FtwSpareLba + FtwDevice->NumberOfSpareBlock) > FvbMapEntry->NumBlocks) { DEBUG ((EFI_D_ERROR, "Ftw: Spare area is out of FV range\n")); ASSERT (FALSE); return; } break; } } } } } if ((FtwDevice->FtwBackupFvb == NULL) || (FtwDevice->FtwFvBlock == NULL) || (FtwDevice->FtwWorkSpaceLba == (EFI_LBA) (-1)) || (FtwDevice->FtwSpareLba == (EFI_LBA) (-1))) { return; } DEBUG ((EFI_D_INFO, "Ftw: Working and spare FVB is ready\n")); // // Calculate the start LBA of working block. Working block is an area which // contains working space in its last block and has the same size as spare // block, unless there are not enough blocks before the block that contains // working space. // FtwDevice->FtwWorkBlockLba = FtwDevice->FtwWorkSpaceLba - FtwDevice->NumberOfSpareBlock + 1; ASSERT ((INT64) (FtwDevice->FtwWorkBlockLba) >= 0); // // Initialize other parameters, and set WorkSpace as FTW_ERASED_BYTE. // FtwDevice->FtwWorkSpace = (UINT8 *) (FtwDevice + 1); FtwDevice->FtwWorkSpaceHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *) FtwDevice->FtwWorkSpace; FtwDevice->FtwLastWriteHeader = NULL; FtwDevice->FtwLastWriteRecord = NULL; // // Refresh the working space data from working block // Status = WorkSpaceRefresh (FtwDevice); ASSERT_EFI_ERROR (Status); // // If the working block workspace is not valid, try the spare block // if (!IsValidWorkSpace (FtwDevice->FtwWorkSpaceHeader)) { // // Read from spare block // Length = FtwDevice->FtwWorkSpaceSize; Status = FtwDevice->FtwBackupFvb->Read ( FtwDevice->FtwBackupFvb, FtwDevice->FtwSpareLba, FtwDevice->FtwWorkSpaceBase, &Length, FtwDevice->FtwWorkSpace ); ASSERT_EFI_ERROR (Status); // // If spare block is valid, then replace working block content. // if (IsValidWorkSpace (FtwDevice->FtwWorkSpaceHeader)) { Status = FlushSpareBlockToWorkingBlock (FtwDevice); DEBUG ((EFI_D_ERROR, "Ftw: Restart working block update in Init() - %r\n", Status)); FtwAbort (&FtwDevice->FtwInstance); // // Refresh work space. // Status = WorkSpaceRefresh (FtwDevice); ASSERT_EFI_ERROR (Status); } else { DEBUG ((EFI_D_ERROR, "Ftw: Both are invalid, init workspace\n")); // // If both are invalid, then initialize work space. // SetMem ( FtwDevice->FtwWorkSpace, FtwDevice->FtwWorkSpaceSize, FTW_ERASED_BYTE ); InitWorkSpaceHeader (FtwDevice->FtwWorkSpaceHeader); // // Initialize the work space // Status = FtwReclaimWorkSpace (FtwDevice, FALSE); ASSERT_EFI_ERROR (Status); } } // // If the FtwDevice->FtwLastWriteRecord is 1st record of write header && // (! SpareComplete) THEN call Abort(). // if ((FtwDevice->FtwLastWriteHeader->HeaderAllocated == FTW_VALID_STATE) && (FtwDevice->FtwLastWriteRecord->SpareComplete != FTW_VALID_STATE) && IsFirstRecordOfWrites (FtwDevice->FtwLastWriteHeader, FtwDevice->FtwLastWriteRecord) ) { DEBUG ((EFI_D_ERROR, "Ftw: Init.. find first record not SpareCompleted, abort()\n")); FtwAbort (&FtwDevice->FtwInstance); } // // If Header is incompleted and the last record has completed, then // call Abort() to set the Header->Complete FLAG. // if ((FtwDevice->FtwLastWriteHeader->Complete != FTW_VALID_STATE) && (FtwDevice->FtwLastWriteRecord->DestinationComplete == FTW_VALID_STATE) && IsLastRecordOfWrites (FtwDevice->FtwLastWriteHeader, FtwDevice->FtwLastWriteRecord) ) { DEBUG ((EFI_D_ERROR, "Ftw: Init.. find last record completed but header not, abort()\n")); FtwAbort (&FtwDevice->FtwInstance); } // // To check the workspace buffer following last Write header/records is EMPTY or not. // If it's not EMPTY, FTW also need to call reclaim(). // FtwHeader = FtwDevice->FtwLastWriteHeader; Offset = (UINT8 *) FtwHeader - FtwDevice->FtwWorkSpace; if (FtwDevice->FtwWorkSpace[Offset] != FTW_ERASED_BYTE) { Offset += WRITE_TOTAL_SIZE (FtwHeader->NumberOfWrites, FtwHeader->PrivateDataSize); } if (!IsErasedFlashBuffer (FtwDevice->FtwWorkSpace + Offset, FtwDevice->FtwWorkSpaceSize - Offset)) { Status = FtwReclaimWorkSpace (FtwDevice, TRUE); ASSERT_EFI_ERROR (Status); } // // Restart if it's boot block // if ((FtwDevice->FtwLastWriteHeader->Complete != FTW_VALID_STATE) && (FtwDevice->FtwLastWriteRecord->SpareComplete == FTW_VALID_STATE) ) { if (FtwDevice->FtwLastWriteRecord->BootBlockUpdate == FTW_VALID_STATE) { Status = FlushSpareBlockToBootBlock (FtwDevice); DEBUG ((EFI_D_ERROR, "Ftw: Restart boot block update - %r\n", Status)); ASSERT_EFI_ERROR (Status); FtwAbort (&FtwDevice->FtwInstance); } else { // // if (SpareCompleted) THEN Restart to fault tolerant write. // FvbHandle = GetFvbByAddress (FtwDevice->FtwLastWriteRecord->FvBaseAddress, &Fvb); if (FvbHandle != NULL) { Status = FtwRestart (&FtwDevice->FtwInstance, FvbHandle); DEBUG ((EFI_D_ERROR, "FtwLite: Restart last write - %r\n", Status)); ASSERT_EFI_ERROR (Status); } FtwAbort (&FtwDevice->FtwInstance); } } // // Hook the protocol API // FtwDevice->FtwInstance.GetMaxBlockSize = FtwGetMaxBlockSize; FtwDevice->FtwInstance.Allocate = FtwAllocate; FtwDevice->FtwInstance.Write = FtwWrite; FtwDevice->FtwInstance.Restart = FtwRestart; FtwDevice->FtwInstance.Abort = FtwAbort; FtwDevice->FtwInstance.GetLastWrite = FtwGetLastWrite; // // Install protocol interface // Status = gBS->InstallProtocolInterface ( &FtwDevice->Handle, &gEfiFaultTolerantWriteProtocolGuid, EFI_NATIVE_INTERFACE, &FtwDevice->FtwInstance ); ASSERT_EFI_ERROR (Status); // // Close the notify event to avoid install FaultTolerantWriteProtocol again. // Status = gBS->CloseEvent (Event); ASSERT_EFI_ERROR (Status); return; }
/** Starts a target block update. This function will record data about write in fault tolerant storage and will complete the write in a recoverable manner, ensuring at all times that either the original contents or the modified contents are available. @param This The pointer to this protocol instance. @param Lba The logical block address of the target block. @param Offset The offset within the target block to place the data. @param Length The number of bytes to write to the target block. @param PrivateData A pointer to private data that the caller requires to complete any pending writes in the event of a fault. @param FvBlockHandle The handle of FVB protocol that provides services for reading, writing, and erasing the target block. @param Buffer The data to write. @retval EFI_SUCCESS The function completed successfully @retval EFI_ABORTED The function could not complete successfully. @retval EFI_BAD_BUFFER_SIZE The input data can't fit within the spare block. Offset + *NumBytes > SpareAreaLength. @retval EFI_ACCESS_DENIED No writes have been allocated. @retval EFI_OUT_OF_RESOURCES Cannot allocate enough memory resource. @retval EFI_NOT_FOUND Cannot find FVB protocol by handle. **/ EFI_STATUS EFIAPI FtwWrite ( IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This, IN EFI_LBA Lba, IN UINTN Offset, IN UINTN Length, IN VOID *PrivateData, IN EFI_HANDLE FvBlockHandle, IN VOID *Buffer ) { EFI_STATUS Status; EFI_FTW_DEVICE *FtwDevice; EFI_FAULT_TOLERANT_WRITE_HEADER *Header; EFI_FAULT_TOLERANT_WRITE_RECORD *Record; EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb; UINTN MyLength; UINTN MyOffset; UINTN MyBufferSize; UINT8 *MyBuffer; UINTN SpareBufferSize; UINT8 *SpareBuffer; UINTN Index; UINT8 *Ptr; EFI_PHYSICAL_ADDRESS FvbPhysicalAddress; FtwDevice = FTW_CONTEXT_FROM_THIS (This); Status = WorkSpaceRefresh (FtwDevice); if (EFI_ERROR (Status)) { return EFI_ABORTED; } Header = FtwDevice->FtwLastWriteHeader; Record = FtwDevice->FtwLastWriteRecord; if (IsErasedFlashBuffer ((UINT8 *) Header, sizeof (EFI_FAULT_TOLERANT_WRITE_HEADER))) { if (PrivateData == NULL) { // // Ftw Write Header is not allocated. // No additional private data, the private data size is zero. Number of record can be set to 1. // Status = FtwAllocate (This, &gEfiCallerIdGuid, 0, 1); if (EFI_ERROR (Status)) { return Status; } } else { // // Ftw Write Header is not allocated // Additional private data is not NULL, the private data size can't be determined. // DEBUG ((EFI_D_ERROR, "Ftw: no allocates space for write record!\n")); DEBUG ((EFI_D_ERROR, "Ftw: Allocate service should be called before Write service!\n")); return EFI_NOT_READY; } } // // If Record is out of the range of Header, return access denied. // if (((UINTN)((UINT8 *) Record - (UINT8 *) Header)) > WRITE_TOTAL_SIZE (Header->NumberOfWrites - 1, Header->PrivateDataSize)) { return EFI_ACCESS_DENIED; } // // Check the COMPLETE flag of last write header // if (Header->Complete == FTW_VALID_STATE) { return EFI_ACCESS_DENIED; } if (Record->DestinationComplete == FTW_VALID_STATE) { return EFI_ACCESS_DENIED; } if ((Record->SpareComplete == FTW_VALID_STATE) && (Record->DestinationComplete != FTW_VALID_STATE)) { return EFI_NOT_READY; } // // Check if the input data can fit within the target block // if ((Offset + Length) > FtwDevice->SpareAreaLength) { return EFI_BAD_BUFFER_SIZE; } // // Get the FVB protocol by handle // Status = FtwGetFvbByHandle (FvBlockHandle, &Fvb); if (EFI_ERROR (Status)) { return EFI_NOT_FOUND; } Status = Fvb->GetPhysicalAddress (Fvb, &FvbPhysicalAddress); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "FtwLite: Get FVB physical address - %r\n", Status)); return EFI_ABORTED; } // // Set BootBlockUpdate FLAG if it's updating boot block. // if (IsBootBlock (FtwDevice, Fvb, Lba)) { Record->BootBlockUpdate = FTW_VALID_STATE; } // // Write the record to the work space. // Record->Lba = Lba; Record->Offset = Offset; Record->Length = Length; Record->FvBaseAddress = FvbPhysicalAddress; if (PrivateData != NULL) { CopyMem ((Record + 1), PrivateData, Header->PrivateDataSize); } MyOffset = (UINT8 *) Record - FtwDevice->FtwWorkSpace; MyLength = RECORD_SIZE (Header->PrivateDataSize); Status = FtwDevice->FtwFvBlock->Write ( FtwDevice->FtwFvBlock, FtwDevice->FtwWorkSpaceLba, FtwDevice->FtwWorkSpaceBase + MyOffset, &MyLength, (UINT8 *) Record ); if (EFI_ERROR (Status)) { return EFI_ABORTED; } // // Record has written to working block, then do the data. // // // Allocate a memory buffer // MyBufferSize = FtwDevice->SpareAreaLength; MyBuffer = AllocatePool (MyBufferSize); if (MyBuffer == NULL) { return EFI_OUT_OF_RESOURCES; } // // Read all original data from target block to memory buffer // Ptr = MyBuffer; for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) { MyLength = FtwDevice->BlockSize; Status = Fvb->Read (Fvb, Lba + Index, 0, &MyLength, Ptr); if (EFI_ERROR (Status)) { FreePool (MyBuffer); return EFI_ABORTED; } Ptr += MyLength; } // // Overwrite the updating range data with // the input buffer content // CopyMem (MyBuffer + Offset, Buffer, Length); // // Try to keep the content of spare block // Save spare block into a spare backup memory buffer (Sparebuffer) // SpareBufferSize = FtwDevice->SpareAreaLength; SpareBuffer = AllocatePool (SpareBufferSize); if (SpareBuffer == NULL) { FreePool (MyBuffer); return EFI_OUT_OF_RESOURCES; } Ptr = SpareBuffer; for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) { MyLength = FtwDevice->BlockSize; Status = FtwDevice->FtwBackupFvb->Read ( FtwDevice->FtwBackupFvb, FtwDevice->FtwSpareLba + Index, 0, &MyLength, Ptr ); if (EFI_ERROR (Status)) { FreePool (MyBuffer); FreePool (SpareBuffer); return EFI_ABORTED; } Ptr += MyLength; } // // Write the memory buffer to spare block // Status = FtwEraseSpareBlock (FtwDevice); Ptr = MyBuffer; for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) { MyLength = FtwDevice->BlockSize; Status = FtwDevice->FtwBackupFvb->Write ( FtwDevice->FtwBackupFvb, FtwDevice->FtwSpareLba + Index, 0, &MyLength, Ptr ); if (EFI_ERROR (Status)) { FreePool (MyBuffer); FreePool (SpareBuffer); return EFI_ABORTED; } Ptr += MyLength; } // // Free MyBuffer // FreePool (MyBuffer); // // Set the SpareComplete in the FTW record, // MyOffset = (UINT8 *) Record - FtwDevice->FtwWorkSpace; Status = FtwUpdateFvState ( FtwDevice->FtwFvBlock, FtwDevice->FtwWorkSpaceLba, FtwDevice->FtwWorkSpaceBase + MyOffset, SPARE_COMPLETED ); if (EFI_ERROR (Status)) { FreePool (SpareBuffer); return EFI_ABORTED; } Record->SpareComplete = FTW_VALID_STATE; // // Since the content has already backuped in spare block, the write is // guaranteed to be completed with fault tolerant manner. // Status = FtwWriteRecord (This, Fvb); if (EFI_ERROR (Status)) { FreePool (SpareBuffer); return EFI_ABORTED; } // // Restore spare backup buffer into spare block , if no failure happened during FtwWrite. // Status = FtwEraseSpareBlock (FtwDevice); Ptr = SpareBuffer; for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) { MyLength = FtwDevice->BlockSize; Status = FtwDevice->FtwBackupFvb->Write ( FtwDevice->FtwBackupFvb, FtwDevice->FtwSpareLba + Index, 0, &MyLength, Ptr ); if (EFI_ERROR (Status)) { FreePool (SpareBuffer); return EFI_ABORTED; } Ptr += MyLength; } // // All success. // FreePool (SpareBuffer); DEBUG ( (EFI_D_ERROR, "Ftw: Write() success, (Lba:Offset)=(%lx:0x%x), Length: 0x%x\n", Lba, Offset, Length) ); return EFI_SUCCESS; }
/** Internal work function to fill in EFI_OPEN_FILE information for the FV @param File Open file handle @param FileName Name of file after device stripped off **/ EFI_STATUS EblFvFileDevicePath ( IN OUT EFI_OPEN_FILE *File, IN CHAR8 *FileName, IN CONST UINT64 OpenMode ) { EFI_STATUS Status; EFI_STATUS GetNextFileStatus; MEDIA_FW_VOL_FILEPATH_DEVICE_PATH DevicePathNode; EFI_DEVICE_PATH_PROTOCOL *DevicePath; UINTN Key; UINT32 AuthenticationStatus; CHAR8 AsciiSection[MAX_PATHNAME]; VOID *Section; UINTN SectionSize; EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb; EFI_LBA Lba; UINTN BlockSize; UINTN NumberOfBlocks; EFI_FIRMWARE_VOLUME_HEADER *FvHeader = NULL; UINTN Index; Status = gBS->HandleProtocol (File->EfiHandle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **)&File->Fv); if (EFI_ERROR (Status)) { return Status; } // Get FVB Info about the handle Status = gBS->HandleProtocol (File->EfiHandle, &gEfiFirmwareVolumeBlockProtocolGuid, (VOID **)&Fvb); if (!EFI_ERROR (Status)) { Status = Fvb->GetPhysicalAddress (Fvb, &File->FvStart); if (!EFI_ERROR (Status)) { FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)File->FvStart; File->FvHeaderSize = sizeof (EFI_FIRMWARE_VOLUME_HEADER); for (Index = 0; FvHeader->BlockMap[Index].Length !=0; Index++) { File->FvHeaderSize += sizeof (EFI_FV_BLOCK_MAP_ENTRY); } for (Lba = 0, File->FvSize = 0, NumberOfBlocks = 0; ; File->FvSize += (BlockSize * NumberOfBlocks), Lba += NumberOfBlocks) { Status = Fvb->GetBlockSize (Fvb, Lba, &BlockSize, &NumberOfBlocks); if (EFI_ERROR (Status)) { break; } } } } DevicePath = DevicePathFromHandle (File->EfiHandle); if (*FileName == '\0') { File->DevicePath = DuplicateDevicePath (DevicePath); File->Size = File->FvSize; File->MaxPosition = File->Size; } else { Key = 0; do { File->FvType = EFI_FV_FILETYPE_ALL; GetNextFileStatus = File->Fv->GetNextFile ( File->Fv, &Key, &File->FvType, &File->FvNameGuid, &File->FvAttributes, &File->Size ); if (!EFI_ERROR (GetNextFileStatus)) { // Compare GUID first Status = CompareGuidToString (&File->FvNameGuid, FileName); if (!EFI_ERROR(Status)) { break; } Section = NULL; Status = File->Fv->ReadSection ( File->Fv, &File->FvNameGuid, EFI_SECTION_USER_INTERFACE, 0, &Section, &SectionSize, &AuthenticationStatus ); if (!EFI_ERROR (Status)) { UnicodeStrToAsciiStr (Section, AsciiSection); if (AsciiStriCmp (FileName, AsciiSection) == 0) { FreePool (Section); break; } FreePool (Section); } } } while (!EFI_ERROR (GetNextFileStatus)); if (EFI_ERROR (GetNextFileStatus)) { return GetNextFileStatus; } if (OpenMode != EFI_SECTION_ALL) { // Calculate the size of the section we are targeting Section = NULL; File->Size = 0; Status = File->Fv->ReadSection ( File->Fv, &File->FvNameGuid, (EFI_SECTION_TYPE)OpenMode, 0, &Section, &File->Size, &AuthenticationStatus ); if (EFI_ERROR (Status)) { return Status; } } File->MaxPosition = File->Size; EfiInitializeFwVolDevicepathNode (&DevicePathNode, &File->FvNameGuid); File->DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&DevicePathNode); } // FVB not required if FV was soft loaded... return EFI_SUCCESS; }
/** Check if an FV is consistent and allocate cache for it. @param FvDevice A pointer to the FvDevice to be checked. @retval EFI_OUT_OF_RESOURCES No enough buffer could be allocated. @retval EFI_VOLUME_CORRUPTED File system is corrupted. @retval EFI_SUCCESS FV is consistent and cache is allocated. **/ EFI_STATUS FvCheck ( IN FV_DEVICE *FvDevice ) { EFI_STATUS Status; EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb; EFI_FVB_ATTRIBUTES_2 FvbAttributes; EFI_FV_BLOCK_MAP_ENTRY *BlockMap; EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; EFI_FIRMWARE_VOLUME_EXT_HEADER *FwVolExtHeader; UINT8 *FwCache; LBA_ENTRY *LbaEntry; FREE_SPACE_ENTRY *FreeSpaceEntry; FFS_FILE_LIST_ENTRY *FfsFileEntry; UINT8 *LbaStart; UINTN Index; EFI_LBA LbaIndex; UINT8 *Ptr; UINTN Size; UINT8 *FreeStart; UINTN FreeSize; UINT8 ErasePolarity; EFI_FFS_FILE_STATE FileState; UINT8 *TopFvAddress; UINTN TestLength; EFI_PHYSICAL_ADDRESS BaseAddress; Fvb = FvDevice->Fvb; Status = Fvb->GetAttributes (Fvb, &FvbAttributes); if (EFI_ERROR (Status)) { return Status; } InitializeListHead (&FvDevice->LbaHeader); InitializeListHead (&FvDevice->FreeSpaceHeader); InitializeListHead (&FvDevice->FfsFileListHeader); FwVolHeader = NULL; Status = GetFwVolHeader (Fvb, &FwVolHeader); if (EFI_ERROR (Status)) { return Status; } ASSERT (FwVolHeader != NULL); FvDevice->IsFfs3Fv = CompareGuid (&FwVolHeader->FileSystemGuid, &gEfiFirmwareFileSystem3Guid); // // Double Check firmware volume header here // if (!VerifyFvHeaderChecksum (FwVolHeader)) { FreePool (FwVolHeader); return EFI_VOLUME_CORRUPTED; } BlockMap = FwVolHeader->BlockMap; // // FwVolHeader->FvLength is the whole FV length including FV header // FwCache = AllocateZeroPool ((UINTN) FwVolHeader->FvLength); if (FwCache == NULL) { FreePool (FwVolHeader); return EFI_OUT_OF_RESOURCES; } FvDevice->CachedFv = (EFI_PHYSICAL_ADDRESS) (UINTN) FwCache; // // Copy to memory // LbaStart = FwCache; LbaIndex = 0; Ptr = NULL; if ((FvbAttributes & EFI_FVB2_MEMORY_MAPPED) != 0) { // // Get volume base address // Status = Fvb->GetPhysicalAddress (Fvb, &BaseAddress); if (EFI_ERROR (Status)) { FreePool (FwVolHeader); return Status; } Ptr = (UINT8 *) ((UINTN) BaseAddress); DEBUG((EFI_D_INFO, "Fv Base Address is 0x%LX\n", BaseAddress)); } // // Copy whole FV into the memory // while ((BlockMap->NumBlocks != 0) || (BlockMap->Length != 0)) { for (Index = 0; Index < BlockMap->NumBlocks; Index++) { LbaEntry = AllocatePool (sizeof (LBA_ENTRY)); if (LbaEntry == NULL) { FreePool (FwVolHeader); FreeFvDeviceResource (FvDevice); return EFI_OUT_OF_RESOURCES; } LbaEntry->LbaIndex = LbaIndex; LbaEntry->StartingAddress = LbaStart; LbaEntry->BlockLength = BlockMap->Length; // // Copy each LBA into memory // if ((FvbAttributes & EFI_FVB2_MEMORY_MAPPED) != 0) { CopyMem (LbaStart, Ptr, BlockMap->Length); Ptr += BlockMap->Length; } else { Size = BlockMap->Length; Status = Fvb->Read ( Fvb, LbaIndex, 0, &Size, LbaStart ); // // Not check EFI_BAD_BUFFER_SIZE, for Size = BlockMap->Length // if (EFI_ERROR (Status)) { FreePool (FwVolHeader); FreeFvDeviceResource (FvDevice); return Status; } } LbaIndex++; LbaStart += BlockMap->Length; InsertTailList (&FvDevice->LbaHeader, &LbaEntry->Link); } BlockMap++; } FvDevice->FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) FwCache; // // it is not used any more, so free FwVolHeader // FreePool (FwVolHeader); // // Scan to check the free space & File list // if ((FvbAttributes & EFI_FVB2_ERASE_POLARITY) != 0) { ErasePolarity = 1; } else { ErasePolarity = 0; } FvDevice->ErasePolarity = ErasePolarity; // // go through the whole FV cache, check the consistence of the FV // if (FvDevice->FwVolHeader->ExtHeaderOffset != 0) { // // Searching for files starts on an 8 byte aligned boundary after the end of the Extended Header if it exists. // FwVolExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *) (UINTN) (FvDevice->CachedFv + FvDevice->FwVolHeader->ExtHeaderOffset); Ptr = (UINT8 *) FwVolExtHeader + FwVolExtHeader->ExtHeaderSize; Ptr = (UINT8 *) ALIGN_POINTER (Ptr, 8); } else { Ptr = (UINT8 *) (UINTN) (FvDevice->CachedFv + FvDevice->FwVolHeader->HeaderLength); } TopFvAddress = (UINT8 *) (UINTN) (FvDevice->CachedFv + FvDevice->FwVolHeader->FvLength); // // Build FFS list & Free Space List here // while (Ptr < TopFvAddress) { TestLength = TopFvAddress - Ptr; if (TestLength > sizeof (EFI_FFS_FILE_HEADER)) { TestLength = sizeof (EFI_FFS_FILE_HEADER); } if (IsBufferErased (ErasePolarity, Ptr, TestLength)) { // // We found free space // FreeStart = Ptr; FreeSize = 0; do { TestLength = TopFvAddress - Ptr; if (TestLength > sizeof (EFI_FFS_FILE_HEADER)) { TestLength = sizeof (EFI_FFS_FILE_HEADER); } if (!IsBufferErased (ErasePolarity, Ptr, TestLength)) { break; } FreeSize += TestLength; Ptr += TestLength; } while (Ptr < TopFvAddress); FreeSpaceEntry = AllocateZeroPool (sizeof (FREE_SPACE_ENTRY)); if (FreeSpaceEntry == NULL) { FreeFvDeviceResource (FvDevice); return EFI_OUT_OF_RESOURCES; } // // Create a Free space entry // FreeSpaceEntry->StartingAddress = FreeStart; FreeSpaceEntry->Length = FreeSize; InsertTailList (&FvDevice->FreeSpaceHeader, &FreeSpaceEntry->Link); continue; } // // double check boundry // if (TestLength < sizeof (EFI_FFS_FILE_HEADER)) { break; } if (!IsValidFFSHeader ( FvDevice->ErasePolarity, (EFI_FFS_FILE_HEADER *) Ptr )) { FileState = GetFileState ( FvDevice->ErasePolarity, (EFI_FFS_FILE_HEADER *) Ptr ); if ((FileState == EFI_FILE_HEADER_INVALID) || (FileState == EFI_FILE_HEADER_CONSTRUCTION)) { if (IS_FFS_FILE2 (Ptr)) { if (!FvDevice->IsFfs3Fv) { DEBUG ((EFI_D_ERROR, "Found a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &((EFI_FFS_FILE_HEADER *) Ptr)->Name)); } Ptr = Ptr + sizeof (EFI_FFS_FILE_HEADER2); } else { Ptr = Ptr + sizeof (EFI_FFS_FILE_HEADER); } continue; } else { // // File system is corrputed, return // FreeFvDeviceResource (FvDevice); return EFI_VOLUME_CORRUPTED; } } if (IS_FFS_FILE2 (Ptr)) { ASSERT (FFS_FILE2_SIZE (Ptr) > 0x00FFFFFF); if (!FvDevice->IsFfs3Fv) { DEBUG ((EFI_D_ERROR, "Found a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &((EFI_FFS_FILE_HEADER *) Ptr)->Name)); Ptr = Ptr + FFS_FILE2_SIZE (Ptr); // // Adjust Ptr to the next 8-byte aligned boundry. // while (((UINTN) Ptr & 0x07) != 0) { Ptr++; } continue; } } if (IsValidFFSFile (FvDevice, (EFI_FFS_FILE_HEADER *) Ptr)) { FileState = GetFileState ( FvDevice->ErasePolarity, (EFI_FFS_FILE_HEADER *) Ptr ); // // check for non-deleted file // if (FileState != EFI_FILE_DELETED) { // // Create a FFS list entry for each non-deleted file // FfsFileEntry = AllocateZeroPool (sizeof (FFS_FILE_LIST_ENTRY)); if (FfsFileEntry == NULL) { FreeFvDeviceResource (FvDevice); return EFI_OUT_OF_RESOURCES; } FfsFileEntry->FfsHeader = Ptr; InsertTailList (&FvDevice->FfsFileListHeader, &FfsFileEntry->Link); } if (IS_FFS_FILE2 (Ptr)) { Ptr = Ptr + FFS_FILE2_SIZE (Ptr); } else { Ptr = Ptr + FFS_FILE_SIZE (Ptr); } // // Adjust Ptr to the next 8-byte aligned boundry. // while (((UINTN) Ptr & 0x07) != 0) { Ptr++; } } else { // // File system is corrupted, return // FreeFvDeviceResource (FvDevice); return EFI_VOLUME_CORRUPTED; } } FvDevice->CurrentFfsFile = NULL; return EFI_SUCCESS; }
/** The security handler is used to abstract platform-specific policy from the DXE core response to an attempt to use a file that returns a given status for the authentication check from the section extraction protocol. The possible responses in a given SAP implementation may include locking flash upon failure to authenticate, attestation logging for all signed drivers, and other exception operations. The File parameter allows for possible logging within the SAP of the driver. If File is NULL, then EFI_INVALID_PARAMETER is returned. If the file specified by File with an authentication status specified by AuthenticationStatus is safe for the DXE Core to use, then EFI_SUCCESS is returned. If the file specified by File with an authentication status specified by AuthenticationStatus is not safe for the DXE Core to use under any circumstances, then EFI_ACCESS_DENIED is returned. If the file specified by File with an authentication status specified by AuthenticationStatus is not safe for the DXE Core to use right now, but it might be possible to use it at a future time, then EFI_SECURITY_VIOLATION is returned. @param[in] AuthenticationStatus This is the authentication status returned from the securitymeasurement services for the input file. @param[in] File This is a pointer to the device path of the file that is being dispatched. This will optionally be used for logging. @param[in] FileBuffer File buffer matches the input file device path. @param[in] FileSize Size of File buffer matches the input file device path. @param[in] BootPolicy A boot policy that was used to call LoadImage() UEFI service. @retval EFI_SUCCESS The file specified by DevicePath and non-NULL FileBuffer did authenticate, and the platform policy dictates that the DXE Foundation may use the file. @retval other error value **/ EFI_STATUS EFIAPI DxeTpmMeasureBootHandler ( IN UINT32 AuthenticationStatus, IN CONST EFI_DEVICE_PATH_PROTOCOL *File, IN VOID *FileBuffer, IN UINTN FileSize, IN BOOLEAN BootPolicy ) { EFI_TCG_PROTOCOL *TcgProtocol; EFI_STATUS Status; TCG_EFI_BOOT_SERVICE_CAPABILITY ProtocolCapability; UINT32 TCGFeatureFlags; EFI_PHYSICAL_ADDRESS EventLogLocation; EFI_PHYSICAL_ADDRESS EventLogLastEntry; EFI_DEVICE_PATH_PROTOCOL *DevicePathNode; EFI_DEVICE_PATH_PROTOCOL *OrigDevicePathNode; EFI_HANDLE Handle; EFI_HANDLE TempHandle; BOOLEAN ApplicationRequired; PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol; EFI_PHYSICAL_ADDRESS FvAddress; UINT32 Index; Status = gBS->LocateProtocol (&gEfiTcgProtocolGuid, NULL, (VOID **) &TcgProtocol); if (EFI_ERROR (Status)) { // // TCG protocol is not installed. So, TPM is not present. // Don't do any measurement, and directly return EFI_SUCCESS. // return EFI_SUCCESS; } ProtocolCapability.Size = (UINT8) sizeof (ProtocolCapability); Status = TcgProtocol->StatusCheck ( TcgProtocol, &ProtocolCapability, &TCGFeatureFlags, &EventLogLocation, &EventLogLastEntry ); if (EFI_ERROR (Status) || ProtocolCapability.TPMDeactivatedFlag) { // // TPM device doesn't work or activate. // return EFI_SUCCESS; } // // Copy File Device Path // OrigDevicePathNode = DuplicateDevicePath (File); // // 1. Check whether this device path support BlockIo protocol. // Is so, this device path may be a GPT device path. // DevicePathNode = OrigDevicePathNode; Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &DevicePathNode, &Handle); if (!EFI_ERROR (Status) && !mMeasureGptTableFlag) { // // Find the gpt partion on the given devicepath // DevicePathNode = OrigDevicePathNode; ASSERT (DevicePathNode != NULL); while (!IsDevicePathEnd (DevicePathNode)) { // // Find the Gpt partition // if (DevicePathType (DevicePathNode) == MEDIA_DEVICE_PATH && DevicePathSubType (DevicePathNode) == MEDIA_HARDDRIVE_DP) { // // Check whether it is a gpt partition or not // if (((HARDDRIVE_DEVICE_PATH *) DevicePathNode)->MBRType == MBR_TYPE_EFI_PARTITION_TABLE_HEADER && ((HARDDRIVE_DEVICE_PATH *) DevicePathNode)->SignatureType == SIGNATURE_TYPE_GUID) { // // Change the partition device path to its parent device path (disk) and get the handle. // DevicePathNode->Type = END_DEVICE_PATH_TYPE; DevicePathNode->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE; DevicePathNode = OrigDevicePathNode; Status = gBS->LocateDevicePath ( &gEfiDiskIoProtocolGuid, &DevicePathNode, &Handle ); if (!EFI_ERROR (Status)) { // // Measure GPT disk. // Status = TcgMeasureGptTable (TcgProtocol, Handle); if (!EFI_ERROR (Status)) { // // GPT disk check done. // mMeasureGptTableFlag = TRUE; } } FreePool (OrigDevicePathNode); OrigDevicePathNode = DuplicateDevicePath (File); ASSERT (OrigDevicePathNode != NULL); break; } } DevicePathNode = NextDevicePathNode (DevicePathNode); } } // // 2. Measure PE image. // ApplicationRequired = FALSE; // // Check whether this device path support FVB protocol. // DevicePathNode = OrigDevicePathNode; Status = gBS->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid, &DevicePathNode, &Handle); if (!EFI_ERROR (Status)) { // // Don't check FV image, and directly return EFI_SUCCESS. // It can be extended to the specific FV authentication according to the different requirement. // if (IsDevicePathEnd (DevicePathNode)) { return EFI_SUCCESS; } // // The PE image from unmeasured Firmware volume need be measured // The PE image from measured Firmware volume will be mearsured according to policy below. // If it is driver, do not measure // If it is application, still measure. // ApplicationRequired = TRUE; if (mCacheMeasuredHandle != Handle && mMeasuredHobData != NULL) { // // Search for Root FV of this PE image // TempHandle = Handle; do { Status = gBS->HandleProtocol( TempHandle, &gEfiFirmwareVolumeBlockProtocolGuid, (VOID**)&FvbProtocol ); TempHandle = FvbProtocol->ParentHandle; } while (!EFI_ERROR(Status) && FvbProtocol->ParentHandle != NULL); // // Search in measured FV Hob // Status = FvbProtocol->GetPhysicalAddress(FvbProtocol, &FvAddress); if (EFI_ERROR(Status)){ return Status; } ApplicationRequired = FALSE; for (Index = 0; Index < mMeasuredHobData->Num; Index++) { if(mMeasuredHobData->MeasuredFvBuf[Index].BlobBase == FvAddress) { // // Cache measured FV for next measurement // mCacheMeasuredHandle = Handle; ApplicationRequired = TRUE; break; } } } } // // File is not found. // if (FileBuffer == NULL) { Status = EFI_SECURITY_VIOLATION; goto Finish; } mImageSize = FileSize; mFileBuffer = FileBuffer; // // Measure PE Image // DevicePathNode = OrigDevicePathNode; ZeroMem (&ImageContext, sizeof (ImageContext)); ImageContext.Handle = (VOID *) FileBuffer; ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) DxeTpmMeasureBootLibImageRead; // // Get information about the image being loaded // Status = PeCoffLoaderGetImageInfo (&ImageContext); if (EFI_ERROR (Status)) { // // The information can't be got from the invalid PeImage // goto Finish; } // // Measure only application if Application flag is set // Measure drivers and applications if Application flag is not set // if ((!ApplicationRequired) || (ApplicationRequired && ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION)) { // // Print the image path to be measured. // DEBUG_CODE_BEGIN (); CHAR16 *ToText; ToText = ConvertDevicePathToText ( DevicePathNode, FALSE, TRUE ); if (ToText != NULL) { DEBUG ((DEBUG_INFO, "The measured image path is %s.\n", ToText)); FreePool (ToText); } DEBUG_CODE_END (); // // Measure PE image into TPM log. // Status = TcgMeasurePeImage ( TcgProtocol, (EFI_PHYSICAL_ADDRESS) (UINTN) FileBuffer, FileSize, (UINTN) ImageContext.ImageAddress, ImageContext.ImageType, DevicePathNode ); } // // Done, free the allocated resource. // Finish: if (OrigDevicePathNode != NULL) { FreePool (OrigDevicePathNode); } return Status; }
/** Gets LBA of block and offset by given address. This function gets the Logical Block Address (LBA) of firmware volume block containing the given address, and the offset of address on the block. @param[in] Address Address which should be contained by returned FVB handle. @param[out] Lba The pointer to LBA for output. @param[out] Offset The pointer to offset for output. @retval EFI_SUCCESS LBA and offset successfully returned. @retval EFI_NOT_FOUND Failed to find FVB handle by address. @retval EFI_ABORTED Failed to find valid LBA and offset. **/ EFI_STATUS GetLbaAndOffsetByAddress ( IN EFI_PHYSICAL_ADDRESS Address, OUT EFI_LBA *Lba, OUT UINTN *Offset ) { EFI_STATUS Status; EFI_HANDLE FvbHandle; EFI_PHYSICAL_ADDRESS FvbBaseAddress; EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb; EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; EFI_FV_BLOCK_MAP_ENTRY *FvbMapEntry; UINT32 LbaIndex; *Lba = (EFI_LBA) (-1); *Offset = 0; // // Gets firmware volume block handle by given address. // Status = GetFvbHandleByAddress (Address, &FvbHandle); if (EFI_ERROR (Status)) { return Status; } Status = gBS->HandleProtocol ( FvbHandle, &gEfiFirmwareVolumeBlockProtocolGuid, (VOID **) &Fvb ); if (EFI_ERROR (Status)) { return Status; } // // Get the Base Address of FV // Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress); if (EFI_ERROR (Status)) { return Status; } FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress); // // Get the (LBA, Offset) of Address // if ((Address >= FvbBaseAddress) && (Address <= (FvbBaseAddress + FwVolHeader->FvLength))) { if ((FwVolHeader->FvLength) > (FwVolHeader->HeaderLength)) { // // BUGBUG: Assume one FV has one type of BlockLength // FvbMapEntry = &FwVolHeader->BlockMap[0]; for (LbaIndex = 1; LbaIndex <= FvbMapEntry->NumBlocks; LbaIndex += 1) { if (Address < (FvbBaseAddress + FvbMapEntry->Length * LbaIndex)) { // // Found the (Lba, Offset) // *Lba = LbaIndex - 1; *Offset = (UINTN) (Address - (FvbBaseAddress + FvbMapEntry->Length * (LbaIndex - 1))); return EFI_SUCCESS; } } } } return EFI_ABORTED; }
/** Firmware volume inherits authentication status from the FV image file and section(in another firmware volume) where it came from or propagated from PEI-phase. @param FvDevice A pointer to the FvDevice. **/ VOID FwVolInheritAuthenticationStatus ( IN FV_DEVICE *FvDevice ) { EFI_STATUS Status; EFI_FIRMWARE_VOLUME_HEADER *CachedFvHeader; EFI_FIRMWARE_VOLUME_EXT_HEADER *CachedFvExtHeader; EFI_FIRMWARE_VOLUME2_PROTOCOL *ParentFvProtocol; UINTN Key; EFI_GUID FileNameGuid; EFI_FV_FILETYPE FileType; EFI_FV_FILE_ATTRIBUTES FileAttributes; UINTN FileSize; EFI_SECTION_TYPE SectionType; UINT32 AuthenticationStatus; EFI_FIRMWARE_VOLUME_HEADER *FvHeader; EFI_FIRMWARE_VOLUME_EXT_HEADER *FvExtHeader; UINTN BufferSize; EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb; EFI_FVB_ATTRIBUTES_2 FvbAttributes; EFI_PHYSICAL_ADDRESS BaseAddress; EFI_PEI_HOB_POINTERS Fv3Hob; if (FvDevice->Fv.ParentHandle != NULL) { CachedFvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) FvDevice->CachedFv; // // By Parent Handle, find out the FV image file and section(in another firmware volume) where the firmware volume came from // Status = gBS->HandleProtocol (FvDevice->Fv.ParentHandle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **) &ParentFvProtocol); if (!EFI_ERROR (Status) && (ParentFvProtocol != NULL)) { Key = 0; do { FileType = EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE; Status = ParentFvProtocol->GetNextFile ( ParentFvProtocol, &Key, &FileType, &FileNameGuid, &FileAttributes, &FileSize ); if (EFI_ERROR (Status)) { return; } SectionType = EFI_SECTION_FIRMWARE_VOLUME_IMAGE; FvHeader = NULL; BufferSize = 0; Status = ParentFvProtocol->ReadSection ( ParentFvProtocol, &FileNameGuid, SectionType, 0, (VOID **) &FvHeader, &BufferSize, &AuthenticationStatus ); if (!EFI_ERROR (Status)) { if ((FvHeader->FvLength == CachedFvHeader->FvLength) && (FvHeader->ExtHeaderOffset == CachedFvHeader->ExtHeaderOffset)) { if (FvHeader->ExtHeaderOffset != 0) { // // Both FVs contain extension header, then compare their FV Name GUID // FvExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *) ((UINTN) FvHeader + FvHeader->ExtHeaderOffset); CachedFvExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *) ((UINTN) CachedFvHeader + CachedFvHeader->ExtHeaderOffset); if (CompareGuid (&FvExtHeader->FvName, &CachedFvExtHeader->FvName)) { // // Found the FV image section where the firmware volume came from, // and then inherit authentication status from it. // FvDevice->AuthenticationStatus = AuthenticationStatus; FreePool ((VOID *) FvHeader); return; } } else { // // Both FVs don't contain extension header, then compare their whole FV Image. // if (CompareMem ((VOID *) FvHeader, (VOID *) CachedFvHeader, (UINTN) FvHeader->FvLength) == 0) { // // Found the FV image section where the firmware volume came from // and then inherit authentication status from it. // FvDevice->AuthenticationStatus = AuthenticationStatus; FreePool ((VOID *) FvHeader); return; } } } FreePool ((VOID *) FvHeader); } } while (TRUE); } } else { Fvb = FvDevice->Fvb; Status = Fvb->GetAttributes (Fvb, &FvbAttributes); if (EFI_ERROR (Status)) { return; } if ((FvbAttributes & EFI_FVB2_MEMORY_MAPPED) != 0) { // // Get volume base address // Status = Fvb->GetPhysicalAddress (Fvb, &BaseAddress); if (EFI_ERROR (Status)) { return; } // // Get the authentication status propagated from PEI-phase to DXE. // Fv3Hob.Raw = GetHobList (); while ((Fv3Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV3, Fv3Hob.Raw)) != NULL) { if (Fv3Hob.FirmwareVolume3->BaseAddress == BaseAddress) { FvDevice->AuthenticationStatus = Fv3Hob.FirmwareVolume3->AuthenticationStatus; return; } Fv3Hob.Raw = GET_NEXT_HOB (Fv3Hob); } } } }