X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=MdeModulePkg%2FCore%2FDxe%2FFwVolBlock%2FFwVolBlock.c;h=95174c1e46fbb10f50b217f35d9a0dc106ab3d24;hp=e90a10bfdc1bb3aee228e2b3df9d75812a942ea4;hb=9d510e61fceee7b92955ef9a3c20343752d8ce3f;hpb=0c2b5da80e9551286cd02a92d91090290ae2d816 diff --git a/MdeModulePkg/Core/Dxe/FwVolBlock/FwVolBlock.c b/MdeModulePkg/Core/Dxe/FwVolBlock/FwVolBlock.c index e90a10bfdc..95174c1e46 100644 --- a/MdeModulePkg/Core/Dxe/FwVolBlock/FwVolBlock.c +++ b/MdeModulePkg/Core/Dxe/FwVolBlock/FwVolBlock.c @@ -1,51 +1,67 @@ -/*++ +/** @file + Implementations for Firmware Volume Block protocol. -Copyright (c) 2006, 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 -which 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. + It consumes FV HOBs and creates read-only Firmare Volume Block protocol + instances for each of them. -Module Name: +Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent - FwVolBlock.c +**/ -Abstract: +#include "DxeMain.h" +#include "FwVolBlock.h" - Firmware Volume Block protocol.. Consumes FV hobs and creates - appropriate block protocols. - - Also consumes NT_NON_MM_FV envinronment variable and produces appropriate - block protocols fro them also... (this is TBD) - ---*/ - -#include - - -EFI_FW_VOL_BLOCK_DEVICE mFwVolBlock = { - FVB_DEVICE_SIGNATURE, - NULL, +FV_MEMMAP_DEVICE_PATH mFvMemmapDevicePathTemplate = { { { + HARDWARE_DEVICE_PATH, + HW_MEMMAP_DP, { - HARDWARE_DEVICE_PATH, - HW_MEMMAP_DP, - { (UINT8)(sizeof (MEMMAP_DEVICE_PATH)), (UINT8)(sizeof (MEMMAP_DEVICE_PATH) >> 8) } - }, - EfiMemoryMappedIO, - (EFI_PHYSICAL_ADDRESS)0, - (EFI_PHYSICAL_ADDRESS)0, + (UINT8)(sizeof (MEMMAP_DEVICE_PATH)), + (UINT8)(sizeof (MEMMAP_DEVICE_PATH) >> 8) + } }, + EfiMemoryMappedIO, + (EFI_PHYSICAL_ADDRESS) 0, + (EFI_PHYSICAL_ADDRESS) 0, + }, + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, { - END_DEVICE_PATH_TYPE, - END_ENTIRE_DEVICE_PATH_SUBTYPE, - { END_DEVICE_PATH_LENGTH, 0 } + END_DEVICE_PATH_LENGTH, + 0 + } + } +}; + +FV_PIWG_DEVICE_PATH mFvPIWGDevicePathTemplate = { + { + { + MEDIA_DEVICE_PATH, + MEDIA_PIWG_FW_VOL_DP, + { + (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH)), + (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH) >> 8) + } }, + { 0 } }, + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { + END_DEVICE_PATH_LENGTH, + 0 + } + } +}; + +EFI_FW_VOL_BLOCK_DEVICE mFwVolBlock = { + FVB_DEVICE_SIGNATURE, + NULL, + NULL, { FwVolBlockGetAttributes, (EFI_FVB_SET_ATTRIBUTES)FwVolBlockSetAttributes, @@ -54,111 +70,127 @@ EFI_FW_VOL_BLOCK_DEVICE mFwVolBlock = { FwVolBlockReadBlock, (EFI_FVB_WRITE)FwVolBlockWriteBlock, (EFI_FVB_ERASE_BLOCKS)FwVolBlockEraseBlock, - NULL + NULL }, 0, NULL, 0, + 0, 0 }; +/** + Retrieves Volume attributes. No polarity translations are done. + + @param This Calling context + @param Attributes output buffer which contains attributes + @retval EFI_SUCCESS The firmware volume attributes were returned. + +**/ EFI_STATUS EFIAPI FwVolBlockGetAttributes ( IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, - OUT EFI_FVB_ATTRIBUTES *Attributes + OUT EFI_FVB_ATTRIBUTES_2 *Attributes ) -/*++ - -Routine Description: - Retrieves Volume attributes. No polarity translations are done. - -Arguments: - This - Calling context - Attributes - output buffer which contains attributes - -Returns: - EFI_SUCCESS - The firmware volume attributes were returned. - ---*/ { EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; - + FvbDevice = FVB_DEVICE_FROM_THIS (This); // // Since we are read only, it's safe to get attributes data from our in-memory copy. // - *Attributes = FvbDevice->FvbAttributes; + *Attributes = FvbDevice->FvbAttributes & ~EFI_FVB2_WRITE_STATUS; return EFI_SUCCESS; } + +/** + Modifies the current settings of the firmware volume according to the input parameter. + + @param This Calling context + @param Attributes input buffer which contains attributes + + @retval EFI_SUCCESS The firmware volume attributes were returned. + @retval EFI_INVALID_PARAMETER The attributes requested are in conflict with + the capabilities as declared in the firmware + volume header. + @retval EFI_UNSUPPORTED Not supported. + +**/ EFI_STATUS EFIAPI FwVolBlockSetAttributes ( IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, - IN CONST EFI_FVB_ATTRIBUTES *Attributes + IN CONST EFI_FVB_ATTRIBUTES_2 *Attributes ) -/*++ - -Routine Description: - Modifies the current settings of the firmware volume according to the input parameter. - -Arguments: - This - Calling context - Attributes - input buffer which contains attributes - -Returns: - EFI_SUCCESS - The firmware volume attributes were returned. - EFI_INVALID_PARAMETER - The attributes requested are in conflict with the capabilities as - declared in the firmware volume header. - EFI_UNSUPPORTED - Not supported. ---*/ { return EFI_UNSUPPORTED; } + +/** + The EraseBlock() function erases one or more blocks as denoted by the + variable argument list. The entire parameter list of blocks must be verified + prior to erasing any blocks. If a block is requested that does not exist + within the associated firmware volume (it has a larger index than the last + block of the firmware volume), the EraseBlock() function must return + EFI_INVALID_PARAMETER without modifying the contents of the firmware volume. + + @param This Calling context + @param ... Starting LBA followed by Number of Lba to erase. + a -1 to terminate the list. + + @retval EFI_SUCCESS The erase request was successfully completed. + @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled + state. + @retval EFI_DEVICE_ERROR The block device is not functioning correctly + and could not be written. The firmware device + may have been partially erased. + @retval EFI_INVALID_PARAMETER One or more of the LBAs listed in the variable + argument list do + @retval EFI_UNSUPPORTED Not supported. + +**/ EFI_STATUS EFIAPI FwVolBlockEraseBlock ( IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, ... ) -/*++ - -Routine Description: - The EraseBlock() function erases one or more blocks as denoted by the -variable argument list. The entire parameter list of blocks must be verified -prior to erasing any blocks. If a block is requested that does not exist -within the associated firmware volume (it has a larger index than the last -block of the firmware volume), the EraseBlock() function must return -EFI_INVALID_PARAMETER without modifying the contents of the firmware volume. - -Arguments: - This - Calling context - ... - Starting LBA followed by Number of Lba to erase. a -1 to terminate - the list. - -Returns: - EFI_SUCCESS - The erase request was successfully completed. - EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state. - EFI_DEVICE_ERROR - The block device is not functioning correctly and could not be - written. The firmware device may have been partially erased. - EFI_INVALID_PARAMETER - One or more of the LBAs listed in the variable argument list do - EFI_UNSUPPORTED - Not supported. - ---*/ { return EFI_UNSUPPORTED; } + +/** + Read the specified number of bytes from the block to the input buffer. + + @param This Indicates the calling context. + @param Lba The starting logical block index to read. + @param Offset Offset into the block at which to begin reading. + @param NumBytes Pointer to a UINT32. At entry, *NumBytes + contains the total size of the buffer. At exit, + *NumBytes contains the total number of bytes + actually read. + @param Buffer Pinter to a caller-allocated buffer that + contains the destine for the read. + + @retval EFI_SUCCESS The firmware volume was read successfully. + @retval EFI_BAD_BUFFER_SIZE The read was attempted across an LBA boundary. + @retval EFI_ACCESS_DENIED Access denied. + @retval EFI_DEVICE_ERROR The block device is malfunctioning and could not + be read. + +**/ EFI_STATUS EFIAPI FwVolBlockReadBlock ( @@ -168,27 +200,6 @@ FwVolBlockReadBlock ( IN OUT UINTN *NumBytes, IN OUT UINT8 *Buffer ) -/*++ - -Routine Description: - Read the specified number of bytes from the block to the input buffer. - -Arguments: - This - Indicates the calling context. - Lba - The starting logical block index to read. - Offset - Offset into the block at which to begin reading. - NumBytes - Pointer to a UINT32. At entry, *NumBytes contains the - total size of the buffer. At exit, *NumBytes contains the - total number of bytes actually read. - Buffer - Pinter to a caller-allocated buffer that contains the destine - for the read. - -Returns: - EFI_SUCCESS - The firmware volume was read successfully. - EFI_BAD_BUFFER_SIZE - The read was attempted across an LBA boundary. - EFI_ACCESS_DENIED - Access denied. - EFI_DEVICE_ERROR - The block device is malfunctioning and could not be read. ---*/ { EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; @@ -196,17 +207,17 @@ Returns: UINTN LbaStart; UINTN NumOfBytesRead; UINTN LbaIndex; - + FvbDevice = FVB_DEVICE_FROM_THIS (This); // // Check if This FW can be read // - if ((FvbDevice->FvbAttributes & EFI_FVB_READ_STATUS) == 0) { + if ((FvbDevice->FvbAttributes & EFI_FVB2_READ_STATUS) == 0) { return EFI_ACCESS_DENIED; } - - LbaIndex = (UINTN)Lba; + + LbaIndex = (UINTN) Lba; if (LbaIndex >= FvbDevice->NumBlocks) { // // Invalid Lba, read nothing. @@ -214,41 +225,66 @@ Returns: *NumBytes = 0; return EFI_BAD_BUFFER_SIZE; } - + if (Offset > FvbDevice->LbaCache[LbaIndex].Length) { // - // all exceed boundry, read nothing. + // all exceed boundary, read nothing. // *NumBytes = 0; return EFI_BAD_BUFFER_SIZE; } - + NumOfBytesRead = *NumBytes; if (Offset + NumOfBytesRead > FvbDevice->LbaCache[LbaIndex].Length) { // - // partial exceed boundry, read data from current postion to end. + // partial exceed boundary, read data from current postion to end. // NumOfBytesRead = FvbDevice->LbaCache[LbaIndex].Length - Offset; } - + LbaStart = FvbDevice->LbaCache[LbaIndex].Base; - FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)((UINTN)FvbDevice->BaseAddress); - LbaOffset = (UINT8 *)FwVolHeader + LbaStart + Offset; + FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)((UINTN) FvbDevice->BaseAddress); + LbaOffset = (UINT8 *) FwVolHeader + LbaStart + Offset; // // Perform read operation // CopyMem (Buffer, LbaOffset, NumOfBytesRead); - + if (NumOfBytesRead == *NumBytes) { return EFI_SUCCESS; } - + *NumBytes = NumOfBytesRead; return EFI_BAD_BUFFER_SIZE; } - + + +/** + Writes the specified number of bytes from the input buffer to the block. + + @param This Indicates the calling context. + @param Lba The starting logical block index to write to. + @param Offset Offset into the block at which to begin writing. + @param NumBytes Pointer to a UINT32. At entry, *NumBytes + contains the total size of the buffer. At exit, + *NumBytes contains the total number of bytes + actually written. + @param Buffer Pinter to a caller-allocated buffer that + contains the source for the write. + + @retval EFI_SUCCESS The firmware volume was written successfully. + @retval EFI_BAD_BUFFER_SIZE The write was attempted across an LBA boundary. + On output, NumBytes contains the total number of + bytes actually written. + @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled + state. + @retval EFI_DEVICE_ERROR The block device is malfunctioning and could not + be written. + @retval EFI_UNSUPPORTED Not supported. + +**/ EFI_STATUS EFIAPI FwVolBlockWriteBlock ( @@ -258,67 +294,60 @@ FwVolBlockWriteBlock ( IN OUT UINTN *NumBytes, IN UINT8 *Buffer ) -/*++ - -Routine Description: - Writes the specified number of bytes from the input buffer to the block. - -Arguments: - This - Indicates the calling context. - Lba - The starting logical block index to write to. - Offset - Offset into the block at which to begin writing. - NumBytes - Pointer to a UINT32. At entry, *NumBytes contains the - total size of the buffer. At exit, *NumBytes contains the - total number of bytes actually written. - Buffer - Pinter to a caller-allocated buffer that contains the source - for the write. - -Returns: - EFI_SUCCESS - The firmware volume was written successfully. - EFI_BAD_BUFFER_SIZE - The write was attempted across an LBA boundary. On output, - NumBytes contains the total number of bytes actually written. - EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state. - EFI_DEVICE_ERROR - The block device is malfunctioning and could not be written. - EFI_UNSUPPORTED - Not supported. ---*/ { return EFI_UNSUPPORTED; } - + + +/** + Get Fvb's base address. + + @param This Indicates the calling context. + @param Address Fvb device base address. + + @retval EFI_SUCCESS Successfully got Fvb's base address. + @retval EFI_UNSUPPORTED Not supported. + +**/ EFI_STATUS EFIAPI FwVolBlockGetPhysicalAddress ( IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, OUT EFI_PHYSICAL_ADDRESS *Address ) -/*++ - -Routine Description: - Get Fvb's base address. - -Arguments: - This - Indicates the calling context. - Address - Fvb device base address. - -Returns: - EFI_SUCCESS - Successfully got Fvb's base address. - EFI_UNSUPPORTED - Not supported. ---*/ { EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; - + FvbDevice = FVB_DEVICE_FROM_THIS (This); - - if (FvbDevice->FvbAttributes & EFI_FVB_MEMORY_MAPPED) { + + if ((FvbDevice->FvbAttributes & EFI_FVB2_MEMORY_MAPPED) != 0) { *Address = FvbDevice->BaseAddress; return EFI_SUCCESS; } - + return EFI_UNSUPPORTED; } + +/** + Retrieves the size in bytes of a specific block within a firmware volume. + + @param This Indicates the calling context. + @param Lba Indicates the block for which to return the + size. + @param BlockSize Pointer to a caller-allocated UINTN in which the + size of the block is returned. + @param NumberOfBlocks Pointer to a caller-allocated UINTN in which the + number of consecutive blocks starting with Lba + is returned. All blocks in this range have a + size of BlockSize. + + @retval EFI_SUCCESS The firmware volume base address is returned. + @retval EFI_INVALID_PARAMETER The requested LBA is out of range. + +**/ EFI_STATUS EFIAPI FwVolBlockGetBlockSize ( @@ -327,42 +356,25 @@ FwVolBlockGetBlockSize ( IN OUT UINTN *BlockSize, IN OUT UINTN *NumberOfBlocks ) -/*++ - -Routine Description: - Retrieves the size in bytes of a specific block within a firmware volume. - -Arguments: - This - Indicates the calling context. - Lba - Indicates the block for which to return the size. - BlockSize - Pointer to a caller-allocated UINTN in which the size of the - block is returned. - NumberOfBlocks - Pointer to a caller-allocated UINTN in which the number of - consecutive blocks starting with Lba is returned. All blocks - in this range have a size of BlockSize. -Returns: - EFI_SUCCESS - The firmware volume base address is returned. - EFI_INVALID_PARAMETER - The requested LBA is out of range. ---*/ { UINTN TotalBlocks; EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry; EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; - + FvbDevice = FVB_DEVICE_FROM_THIS (This); - + // // Do parameter checking // if (Lba >= FvbDevice->NumBlocks) { return EFI_INVALID_PARAMETER; } - + FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)((UINTN)FvbDevice->BaseAddress); - + PtrBlockMapEntry = FwVolHeader->BlockMap; - + // // Search the block map for the given block // @@ -375,44 +387,69 @@ Returns: // break; } - + PtrBlockMapEntry++; } - + *BlockSize = PtrBlockMapEntry->Length; *NumberOfBlocks = TotalBlocks - (UINTN)Lba; - + return EFI_SUCCESS; } +/** + + Get FVB authentication status + + @param FvbProtocol FVB protocol. + @return Authentication status. + +**/ +UINT32 +GetFvbAuthenticationStatus ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol + ) +{ + EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; + UINT32 AuthenticationStatus; + + AuthenticationStatus = 0; + FvbDevice = BASE_CR (FvbProtocol, EFI_FW_VOL_BLOCK_DEVICE, FwVolBlockInstance); + if (FvbDevice->Signature == FVB_DEVICE_SIGNATURE) { + AuthenticationStatus = FvbDevice->AuthenticationStatus; + } + + return AuthenticationStatus; +} + +/** + This routine produces a firmware volume block protocol on a given + buffer. + + @param BaseAddress base address of the firmware volume image + @param Length length of the firmware volume image + @param ParentHandle handle of parent firmware volume, if this image + came from an FV image file and section in another firmware + volume (ala capsules) + @param AuthenticationStatus Authentication status inherited, if this image + came from an FV image file and section in another firmware volume. + @param FvProtocol Firmware volume block protocol produced. + + @retval EFI_VOLUME_CORRUPTED Volume corrupted. + @retval EFI_OUT_OF_RESOURCES No enough buffer to be allocated. + @retval EFI_SUCCESS Successfully produced a FVB protocol on given + buffer. + +**/ EFI_STATUS ProduceFVBProtocolOnBuffer ( IN EFI_PHYSICAL_ADDRESS BaseAddress, IN UINT64 Length, IN EFI_HANDLE ParentHandle, + IN UINT32 AuthenticationStatus, OUT EFI_HANDLE *FvProtocol OPTIONAL ) -/*++ - -Routine Description: - This routine produces a firmware volume block protocol on a given - buffer. - -Arguments: - BaseAddress - base address of the firmware volume image - Length - length of the firmware volume image - ParentHandle - handle of parent firmware volume, if this - image came from an FV image file in another - firmware volume (ala capsules) - FvProtocol - Firmware volume block protocol produced. - -Returns: - EFI_VOLUME_CORRUPTED - Volume corrupted. - EFI_OUT_OF_RESOURCES - No enough buffer to be allocated. - EFI_SUCCESS - Successfully produced a FVB protocol on given buffer. - ---*/ { EFI_STATUS Status; EFI_FW_VOL_BLOCK_DEVICE *FvbDev; @@ -420,19 +457,53 @@ Returns: UINTN BlockIndex; UINTN BlockIndex2; UINTN LinearOffset; + UINT32 FvAlignment; EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry; - FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)BaseAddress; + FvAlignment = 0; + FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN) BaseAddress; // // Validate FV Header, if not as expected, return // if (FwVolHeader->Signature != EFI_FVH_SIGNATURE) { return EFI_VOLUME_CORRUPTED; } + // - // Allocate EFI_FW_VOL_BLOCK_DEVICE + // If EFI_FVB2_WEAK_ALIGNMENT is set in the volume header then the first byte of the volume + // can be aligned on any power-of-two boundary. A weakly aligned volume can not be moved from + // its initial linked location and maintain its alignment. // - FvbDev = CoreAllocateCopyPool (sizeof (EFI_FW_VOL_BLOCK_DEVICE), &mFwVolBlock); + if ((FwVolHeader->Attributes & EFI_FVB2_WEAK_ALIGNMENT) != EFI_FVB2_WEAK_ALIGNMENT) { + // + // Get FvHeader alignment + // + FvAlignment = 1 << ((FwVolHeader->Attributes & EFI_FVB2_ALIGNMENT) >> 16); + // + // FvAlignment must be greater than or equal to 8 bytes of the minimum FFS alignment value. + // + if (FvAlignment < 8) { + FvAlignment = 8; + } + if ((UINTN)BaseAddress % FvAlignment != 0) { + // + // FvImage buffer is not at its required alignment. + // + DEBUG (( + DEBUG_ERROR, + "Unaligned FvImage found at 0x%lx:0x%lx, the required alignment is 0x%x\n", + BaseAddress, + Length, + FvAlignment + )); + return EFI_VOLUME_CORRUPTED; + } + } + + // + // Allocate EFI_FW_VOL_BLOCK_DEVICE + // + FvbDev = AllocateCopyPool (sizeof (EFI_FW_VOL_BLOCK_DEVICE), &mFwVolBlock); if (FvbDev == NULL) { return EFI_OUT_OF_RESOURCES; } @@ -440,6 +511,7 @@ Returns: FvbDev->BaseAddress = BaseAddress; FvbDev->FvbAttributes = FwVolHeader->Attributes; FvbDev->FwVolBlockInstance.ParentHandle = ParentHandle; + FvbDev->AuthenticationStatus = AuthenticationStatus; // // Init the block caching fields of the device @@ -447,25 +519,31 @@ Returns: // FvbDev->NumBlocks = 0; for (PtrBlockMapEntry = FwVolHeader->BlockMap; - PtrBlockMapEntry->NumBlocks != 0; - PtrBlockMapEntry++) { + PtrBlockMapEntry->NumBlocks != 0; + PtrBlockMapEntry++) { FvbDev->NumBlocks += PtrBlockMapEntry->NumBlocks; } + // // Second, allocate the cache // - FvbDev->LbaCache = CoreAllocateBootServicesPool (FvbDev->NumBlocks * sizeof (LBA_CACHE)); + if (FvbDev->NumBlocks >= (MAX_ADDRESS / sizeof (LBA_CACHE))) { + CoreFreePool (FvbDev); + return EFI_OUT_OF_RESOURCES; + } + FvbDev->LbaCache = AllocatePool (FvbDev->NumBlocks * sizeof (LBA_CACHE)); if (FvbDev->LbaCache == NULL) { CoreFreePool (FvbDev); return EFI_OUT_OF_RESOURCES; } + // // Last, fill in the cache with the linear address of the blocks // BlockIndex = 0; LinearOffset = 0; for (PtrBlockMapEntry = FwVolHeader->BlockMap; - PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) { + PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) { for (BlockIndex2 = 0; BlockIndex2 < PtrBlockMapEntry->NumBlocks; BlockIndex2++) { FvbDev->LbaCache[BlockIndex].Base = LinearOffset; FvbDev->LbaCache[BlockIndex].Length = PtrBlockMapEntry->Length; @@ -475,22 +553,44 @@ Returns: } // - // Set up the devicepath + // Judget whether FV name guid is produced in Fv extension header // - FvbDev->DevicePath.MemMapDevPath.StartingAddress = BaseAddress; - FvbDev->DevicePath.MemMapDevPath.EndingAddress = BaseAddress + FwVolHeader->FvLength - 1; + if (FwVolHeader->ExtHeaderOffset == 0) { + // + // FV does not contains extension header, then produce MEMMAP_DEVICE_PATH + // + FvbDev->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) AllocateCopyPool (sizeof (FV_MEMMAP_DEVICE_PATH), &mFvMemmapDevicePathTemplate); + if (FvbDev->DevicePath == NULL) { + FreePool (FvbDev); + return EFI_OUT_OF_RESOURCES; + } + ((FV_MEMMAP_DEVICE_PATH *) FvbDev->DevicePath)->MemMapDevPath.StartingAddress = BaseAddress; + ((FV_MEMMAP_DEVICE_PATH *) FvbDev->DevicePath)->MemMapDevPath.EndingAddress = BaseAddress + FwVolHeader->FvLength - 1; + } else { + // + // FV contains extension header, then produce MEDIA_FW_VOL_DEVICE_PATH + // + FvbDev->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) AllocateCopyPool (sizeof (FV_PIWG_DEVICE_PATH), &mFvPIWGDevicePathTemplate); + if (FvbDev->DevicePath == NULL) { + FreePool (FvbDev); + return EFI_OUT_OF_RESOURCES; + } + CopyGuid ( + &((FV_PIWG_DEVICE_PATH *)FvbDev->DevicePath)->FvDevPath.FvName, + (GUID *)(UINTN)(BaseAddress + FwVolHeader->ExtHeaderOffset) + ); + } // // // Attach FvVolBlock Protocol to new handle // Status = CoreInstallMultipleProtocolInterfaces ( - &FvbDev->Handle, - &gEfiFirmwareVolumeBlockProtocolGuid, &FvbDev->FwVolBlockInstance, - &gEfiDevicePathProtocolGuid, &FvbDev->DevicePath, - &gEfiFirmwareVolumeDispatchProtocolGuid, NULL, - NULL - ); + &FvbDev->Handle, + &gEfiFirmwareVolumeBlockProtocolGuid, &FvbDev->FwVolBlockInstance, + &gEfiDevicePathProtocolGuid, FvbDev->DevicePath, + NULL + ); // // If they want the handle back, set it. @@ -503,90 +603,110 @@ Returns: } + +/** + This routine consumes FV hobs and produces instances of FW_VOL_BLOCK_PROTOCOL as appropriate. + + @param ImageHandle The image handle. + @param SystemTable The system table. + + @retval EFI_SUCCESS Successfully initialized firmware volume block + driver. + +**/ EFI_STATUS EFIAPI FwVolBlockDriverInit ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) -/*++ - -Routine Description: - This routine is the driver initialization entry point. It initializes the - libraries, consumes FV hobs and NT_NON_MM_FV environment variable and - produces instances of FW_VOL_BLOCK_PROTOCOL as appropriate. -Arguments: - ImageHandle - The image handle. - SystemTable - The system table. -Returns: - EFI_SUCCESS - Successfully initialized firmware volume block driver. ---*/ { EFI_PEI_HOB_POINTERS FvHob; + EFI_PEI_HOB_POINTERS Fv3Hob; + UINT32 AuthenticationStatus; + // // Core Needs Firmware Volumes to function // FvHob.Raw = GetHobList (); while ((FvHob.Raw = GetNextHob (EFI_HOB_TYPE_FV, FvHob.Raw)) != NULL) { + AuthenticationStatus = 0; + // + // 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 == FvHob.FirmwareVolume->BaseAddress) && + (Fv3Hob.FirmwareVolume3->Length == FvHob.FirmwareVolume->Length)) { + AuthenticationStatus = Fv3Hob.FirmwareVolume3->AuthenticationStatus; + break; + } + Fv3Hob.Raw = GET_NEXT_HOB (Fv3Hob); + } // // Produce an FVB protocol for it // - ProduceFVBProtocolOnBuffer (FvHob.FirmwareVolume->BaseAddress, FvHob.FirmwareVolume->Length, NULL, NULL); + ProduceFVBProtocolOnBuffer (FvHob.FirmwareVolume->BaseAddress, FvHob.FirmwareVolume->Length, NULL, AuthenticationStatus, NULL); FvHob.Raw = GET_NEXT_HOB (FvHob); } + return EFI_SUCCESS; } + +/** + This DXE service routine is used to process a firmware volume. In + particular, it can be called by BDS to process a single firmware + volume found in a capsule. + + Caution: The caller need validate the input firmware volume to follow + PI specification. + DxeCore will trust the input data and process firmware volume directly. + + @param FvHeader pointer to a firmware volume header + @param Size the size of the buffer pointed to by FvHeader + @param FVProtocolHandle the handle on which a firmware volume protocol + was produced for the firmware volume passed in. + + @retval EFI_OUT_OF_RESOURCES if an FVB could not be produced due to lack of + system resources + @retval EFI_VOLUME_CORRUPTED if the volume was corrupted + @retval EFI_SUCCESS a firmware volume protocol was produced for the + firmware volume + +**/ EFI_STATUS +EFIAPI CoreProcessFirmwareVolume ( IN VOID *FvHeader, - IN UINTN Size, + IN UINTN Size, OUT EFI_HANDLE *FVProtocolHandle ) -/*++ - -Routine Description: - This DXE service routine is used to process a firmware volume. In - particular, it can be called by BDS to process a single firmware - volume found in a capsule. - -Arguments: - FvHeader - pointer to a firmware volume header - Size - the size of the buffer pointed to by FvHeader - FVProtocolHandle - the handle on which a firmware volume protocol - was produced for the firmware volume passed in. - -Returns: - EFI_OUT_OF_RESOURCES - if an FVB could not be produced due to lack of - system resources - EFI_VOLUME_CORRUPTED - if the volume was corrupted - EFI_SUCCESS - a firmware volume protocol was produced for the - firmware volume - ---*/ { VOID *Ptr; EFI_STATUS Status; *FVProtocolHandle = NULL; - Status = ProduceFVBProtocolOnBuffer ( - (EFI_PHYSICAL_ADDRESS) (UINTN) FvHeader, - (UINT64)Size, - NULL, + Status = ProduceFVBProtocolOnBuffer ( + (EFI_PHYSICAL_ADDRESS) (UINTN) FvHeader, + (UINT64)Size, + NULL, + 0, FVProtocolHandle ); // // Since in our implementation we use register-protocol-notify to put a // FV protocol on the FVB protocol handle, we can't directly verify that // the FV protocol was produced. Therefore here we will check the handle - // and make sure an FV protocol is on it. This indicates that all went - // well. Otherwise we have to assume that the volume was corrupted + // and make sure an FV protocol is on it. This indicates that all went + // well. Otherwise we have to assume that the volume was corrupted // somehow. // if (!EFI_ERROR(Status)) { + ASSERT (*FVProtocolHandle != NULL); Ptr = NULL; - Status = CoreHandleProtocol (*FVProtocolHandle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **)&Ptr); + Status = CoreHandleProtocol (*FVProtocolHandle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **) &Ptr); if (EFI_ERROR(Status) || (Ptr == NULL)) { return EFI_VOLUME_CORRUPTED; } @@ -596,3 +716,4 @@ Returns: } +