summaryrefslogtreecommitdiff
path: root/EDK/Foundation/Core/Dxe/FwVolBlock/FwVolBlock.c
diff options
context:
space:
mode:
Diffstat (limited to 'EDK/Foundation/Core/Dxe/FwVolBlock/FwVolBlock.c')
-rw-r--r--EDK/Foundation/Core/Dxe/FwVolBlock/FwVolBlock.c621
1 files changed, 621 insertions, 0 deletions
diff --git a/EDK/Foundation/Core/Dxe/FwVolBlock/FwVolBlock.c b/EDK/Foundation/Core/Dxe/FwVolBlock/FwVolBlock.c
new file mode 100644
index 0000000..ebe3964
--- /dev/null
+++ b/EDK/Foundation/Core/Dxe/FwVolBlock/FwVolBlock.c
@@ -0,0 +1,621 @@
+/*++
+
+Copyright (c) 2004 - 2005, 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.
+
+Module Name:
+
+ FwVolBlock.c
+
+Abstract:
+
+ 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 "Tiano.h"
+#include "FwVolBlock.h"
+
+
+EFI_FW_VOL_BLOCK_DEVICE mFwVolBlock = {
+ FVB_DEVICE_SIGNATURE,
+ NULL,
+ {
+ {
+ 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,
+ },
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ END_DEVICE_PATH_LENGTH,
+ 0
+ },
+ },
+ {
+ FwVolBlockGetAttributes,
+ (EFI_FVB_SET_ATTRIBUTES)FwVolBlockSetAttributes,
+ FwVolBlockGetPhysicalAddress,
+ FwVolBlockGetBlockSize,
+ FwVolBlockReadBlock,
+ (EFI_FVB_WRITE)FwVolBlockWriteBlock,
+ (EFI_FVB_ERASE_BLOCKS)FwVolBlockEraseBlock,
+ NULL
+ },
+ 0,
+ NULL,
+ 0,
+ 0
+};
+
+
+
+
+EFI_STATUS
+EFIAPI
+FwVolBlockGetAttributes (
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ OUT EFI_FVB_ATTRIBUTES *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;
+
+ return EFI_SUCCESS;
+}
+
+
+EFI_STATUS
+EFIAPI
+FwVolBlockSetAttributes (
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ IN EFI_FVB_ATTRIBUTES *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;
+}
+
+
+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;
+}
+
+
+EFI_STATUS
+EFIAPI
+FwVolBlockReadBlock (
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ IN EFI_LBA Lba,
+ IN UINTN Offset,
+ IN OUT UINTN *NumBytes,
+ IN 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;
+ UINT8 *LbaOffset;
+ 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) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ LbaIndex = (UINTN)Lba;
+ if (LbaIndex >= FvbDevice->NumBlocks) {
+ //
+ // Invalid Lba, read nothing.
+ //
+ *NumBytes = 0;
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ if (Offset > FvbDevice->LbaCache[LbaIndex].Length) {
+ //
+ // all exceed boundry, 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.
+ //
+ NumOfBytesRead = FvbDevice->LbaCache[LbaIndex].Length - Offset;
+ }
+
+ LbaStart = FvbDevice->LbaCache[LbaIndex].Base;
+ FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)((UINTN)FvbDevice->BaseAddress);
+ LbaOffset = (UINT8 *)FwVolHeader + LbaStart + Offset;
+
+ //
+ // Perform read operation
+ //
+ EfiCommonLibCopyMem (Buffer, LbaOffset, NumOfBytesRead);
+
+ if (NumOfBytesRead == *NumBytes) {
+ return EFI_SUCCESS;
+ }
+
+ *NumBytes = NumOfBytesRead;
+ return EFI_BAD_BUFFER_SIZE;
+}
+
+
+EFI_STATUS
+EFIAPI
+FwVolBlockWriteBlock (
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ IN EFI_LBA Lba,
+ IN UINTN Offset,
+ 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;
+}
+
+
+EFI_STATUS
+EFIAPI
+FwVolBlockGetPhysicalAddress (
+ IN 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) {
+ *Address = FvbDevice->BaseAddress;
+ return EFI_SUCCESS;
+ }
+
+ return EFI_UNSUPPORTED;
+}
+
+
+EFI_STATUS
+EFIAPI
+FwVolBlockGetBlockSize (
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ IN EFI_LBA Lba,
+ OUT UINTN *BlockSize,
+ 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->FvBlockMap;
+
+ //
+ // Search the block map for the given block
+ //
+ TotalBlocks = 0;
+ while ((PtrBlockMapEntry->NumBlocks != 0) || (PtrBlockMapEntry->BlockLength !=0 )) {
+ TotalBlocks += PtrBlockMapEntry->NumBlocks;
+ if (Lba < TotalBlocks) {
+ //
+ // We find the range
+ //
+ break;
+ }
+
+ PtrBlockMapEntry++;
+ }
+
+ *BlockSize = PtrBlockMapEntry->BlockLength;
+ *NumberOfBlocks = TotalBlocks - (UINTN)Lba;
+
+ return EFI_SUCCESS;
+}
+
+
+EFI_STATUS
+ProduceFVBProtocolOnBuffer (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN EFI_HANDLE ParentHandle,
+ 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;
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
+ UINTN BlockIndex;
+ UINTN BlockIndex2;
+ UINTN LinearOffset;
+ EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry;
+
+ 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
+ //
+ FvbDev = CoreAllocateCopyPool (sizeof (EFI_FW_VOL_BLOCK_DEVICE), &mFwVolBlock);
+ if (FvbDev == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ FvbDev->BaseAddress = BaseAddress;
+ FvbDev->FvbAttributes = FwVolHeader->Attributes;
+ FvbDev->FwVolBlockInstance.ParentHandle = ParentHandle;
+
+ //
+ // Init the block caching fields of the device
+ // First, count the number of blocks
+ //
+ FvbDev->NumBlocks = 0;
+ for (PtrBlockMapEntry = FwVolHeader->FvBlockMap;
+ PtrBlockMapEntry->NumBlocks != 0;
+ PtrBlockMapEntry++) {
+ FvbDev->NumBlocks += PtrBlockMapEntry->NumBlocks;
+ }
+ //
+ // Second, allocate the cache
+ //
+ FvbDev->LbaCache = CoreAllocateBootServicesPool (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->FvBlockMap;
+ PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {
+ for (BlockIndex2 = 0; BlockIndex2 < PtrBlockMapEntry->NumBlocks; BlockIndex2++) {
+ FvbDev->LbaCache[BlockIndex].Base = LinearOffset;
+ FvbDev->LbaCache[BlockIndex].Length = PtrBlockMapEntry->BlockLength;
+ LinearOffset += PtrBlockMapEntry->BlockLength;
+ BlockIndex++;
+ }
+ }
+
+ //
+ // Set up the devicepath
+ //
+ FvbDev->DevicePath.MemMapDevPath.StartingAddress = BaseAddress;
+ FvbDev->DevicePath.MemMapDevPath.EndingAddress = BaseAddress + FwVolHeader->FvLength - 1;
+
+ //
+ //
+ // Attach FvVolBlock Protocol to new handle
+ //
+ Status = CoreInstallMultipleProtocolInterfaces (
+ &FvbDev->Handle,
+ &gEfiFirmwareVolumeBlockProtocolGuid, &FvbDev->FwVolBlockInstance,
+ &gEfiDevicePathProtocolGuid, &FvbDev->DevicePath,
+ &gEfiFirmwareVolumeDispatchProtocolGuid, NULL,
+ NULL
+ );
+
+ //
+ // If they want the handle back, set it.
+ //
+ if (FvProtocol != NULL) {
+ *FvProtocol = FvbDev->Handle;
+ }
+
+ return Status;
+}
+
+
+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_STATUS Status;
+ VOID *HobList;
+ EFI_PHYSICAL_ADDRESS BaseAddress;
+ UINT64 Length;
+ EFI_STATUS HobStatus;
+
+ //
+ // First walk hobs and create appropriate FVs.
+ //
+ Status = CoreGetConfigTable (&gEfiHobListGuid, &HobList);
+ //
+ // Core Needs Firmware Volumes to function
+ //
+ ASSERT_EFI_ERROR (Status);
+
+ BaseAddress = 0;
+ Length = 0;
+ HobStatus = GetNextFirmwareVolumeHob (
+ &HobList,
+ &BaseAddress,
+ &Length
+ );
+ while (!EFI_ERROR (HobStatus)) {
+ //
+ // Produce an FVB protocol for it
+ //
+ ProduceFVBProtocolOnBuffer (BaseAddress, Length, NULL, NULL);
+ HobStatus = GetNextFirmwareVolumeHob (
+ &HobList,
+ &BaseAddress,
+ &Length
+ );
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+EFI_STATUS
+CoreProcessFirmwareVolume (
+ IN VOID *FvHeader,
+ 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,
+ 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
+ // somehow.
+ //
+ if (!EFI_ERROR(Status)) {
+ Ptr = NULL;
+ Status = CoreHandleProtocol (*FVProtocolHandle, &gEfiFirmwareVolumeProtocolGuid, &Ptr);
+ if (EFI_ERROR(Status) || (Ptr == NULL)) {
+ return EFI_VOLUME_CORRUPTED;
+ }
+ return EFI_SUCCESS;
+ }
+ return Status;
+}
+
+