+++ /dev/null
-/*++\r
-\r
-Copyright (c) 2006, Intel Corporation \r
-All rights reserved. This program and the accompanying materials \r
-are licensed and made available under the terms and conditions of the BSD License \r
-which accompanies this distribution. The full text of the license may be found at \r
-http://opensource.org/licenses/bsd-license.php \r
- \r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
-\r
-Module Name:\r
-\r
- FwVolBlock.c\r
-\r
-Abstract:\r
-\r
- Firmware Volume Block protocol.. Consumes FV hobs and creates\r
- appropriate block protocols.\r
-\r
- Also consumes NT_NON_MM_FV envinronment variable and produces appropriate\r
- block protocols fro them also... (this is TBD)\r
-\r
---*/\r
-\r
-#include <DxeMain.h>\r
-\r
-\r
-EFI_FW_VOL_BLOCK_DEVICE mFwVolBlock = {\r
- FVB_DEVICE_SIGNATURE,\r
- NULL,\r
- {\r
- {\r
- {\r
- HARDWARE_DEVICE_PATH,\r
- HW_MEMMAP_DP,\r
- { (UINT8)(sizeof (MEMMAP_DEVICE_PATH)), (UINT8)(sizeof (MEMMAP_DEVICE_PATH) >> 8) }\r
- },\r
- EfiMemoryMappedIO,\r
- (EFI_PHYSICAL_ADDRESS)0,\r
- (EFI_PHYSICAL_ADDRESS)0,\r
- },\r
- {\r
- END_DEVICE_PATH_TYPE,\r
- END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
- { END_DEVICE_PATH_LENGTH, 0 } \r
- },\r
- },\r
- {\r
- FwVolBlockGetAttributes,\r
- (EFI_FVB_SET_ATTRIBUTES)FwVolBlockSetAttributes,\r
- FwVolBlockGetPhysicalAddress,\r
- FwVolBlockGetBlockSize,\r
- FwVolBlockReadBlock,\r
- (EFI_FVB_WRITE)FwVolBlockWriteBlock,\r
- (EFI_FVB_ERASE_BLOCKS)FwVolBlockEraseBlock,\r
- NULL \r
- },\r
- 0,\r
- NULL,\r
- 0,\r
- 0\r
-};\r
-\r
-\r
-\r
-\r
-EFI_STATUS\r
-EFIAPI\r
-FwVolBlockGetAttributes (\r
- IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
- OUT EFI_FVB_ATTRIBUTES *Attributes\r
- )\r
-/*++\r
-\r
-Routine Description:\r
- Retrieves Volume attributes. No polarity translations are done.\r
-\r
-Arguments:\r
- This - Calling context\r
- Attributes - output buffer which contains attributes\r
-\r
-Returns:\r
- EFI_SUCCESS - The firmware volume attributes were returned.\r
-\r
---*/\r
-{\r
- EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
- \r
- FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
-\r
- //\r
- // Since we are read only, it's safe to get attributes data from our in-memory copy.\r
- //\r
- *Attributes = FvbDevice->FvbAttributes;\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-\r
-EFI_STATUS\r
-EFIAPI\r
-FwVolBlockSetAttributes (\r
- IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
- IN EFI_FVB_ATTRIBUTES *Attributes\r
- )\r
-/*++\r
-\r
-Routine Description:\r
- Modifies the current settings of the firmware volume according to the input parameter.\r
-\r
-Arguments:\r
- This - Calling context\r
- Attributes - input buffer which contains attributes\r
-\r
-Returns:\r
- EFI_SUCCESS - The firmware volume attributes were returned.\r
- EFI_INVALID_PARAMETER - The attributes requested are in conflict with the capabilities as\r
- declared in the firmware volume header.\r
- EFI_UNSUPPORTED - Not supported.\r
---*/\r
-{\r
- return EFI_UNSUPPORTED;\r
-}\r
-\r
-\r
-EFI_STATUS\r
-EFIAPI\r
-FwVolBlockEraseBlock (\r
- IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
- ...\r
- )\r
-/*++\r
-\r
-Routine Description:\r
- The EraseBlock() function erases one or more blocks as denoted by the \r
-variable argument list. The entire parameter list of blocks must be verified\r
-prior to erasing any blocks. If a block is requested that does not exist \r
-within the associated firmware volume (it has a larger index than the last \r
-block of the firmware volume), the EraseBlock() function must return\r
-EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.\r
-\r
-Arguments:\r
- This - Calling context\r
- ... - Starting LBA followed by Number of Lba to erase. a -1 to terminate\r
- the list.\r
- \r
-Returns:\r
- EFI_SUCCESS - The erase request was successfully completed.\r
- EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state.\r
- EFI_DEVICE_ERROR - The block device is not functioning correctly and could not be\r
- written. The firmware device may have been partially erased.\r
- EFI_INVALID_PARAMETER - One or more of the LBAs listed in the variable argument list do\r
- EFI_UNSUPPORTED - Not supported.\r
- \r
---*/\r
-{\r
- return EFI_UNSUPPORTED;\r
-}\r
-\r
-\r
-EFI_STATUS\r
-EFIAPI\r
-FwVolBlockReadBlock (\r
- IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
- IN EFI_LBA Lba,\r
- IN UINTN Offset,\r
- IN OUT UINTN *NumBytes,\r
- IN UINT8 *Buffer\r
- )\r
-/*++\r
-\r
-Routine Description:\r
- Read the specified number of bytes from the block to the input buffer.\r
-\r
-Arguments:\r
- This - Indicates the calling context.\r
- Lba - The starting logical block index to read.\r
- Offset - Offset into the block at which to begin reading.\r
- NumBytes - Pointer to a UINT32. At entry, *NumBytes contains the\r
- total size of the buffer. At exit, *NumBytes contains the\r
- total number of bytes actually read.\r
- Buffer - Pinter to a caller-allocated buffer that contains the destine\r
- for the read. \r
-\r
-Returns: \r
- EFI_SUCCESS - The firmware volume was read successfully.\r
- EFI_BAD_BUFFER_SIZE - The read was attempted across an LBA boundary.\r
- EFI_ACCESS_DENIED - Access denied.\r
- EFI_DEVICE_ERROR - The block device is malfunctioning and could not be read.\r
---*/\r
-{\r
- EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
- EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
- UINT8 *LbaOffset;\r
- UINTN LbaStart;\r
- UINTN NumOfBytesRead;\r
- UINTN LbaIndex;\r
- \r
- FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
-\r
- //\r
- // Check if This FW can be read\r
- //\r
- if ((FvbDevice->FvbAttributes & EFI_FVB_READ_STATUS) == 0) {\r
- return EFI_ACCESS_DENIED;\r
- }\r
- \r
- LbaIndex = (UINTN)Lba;\r
- if (LbaIndex >= FvbDevice->NumBlocks) {\r
- //\r
- // Invalid Lba, read nothing.\r
- //\r
- *NumBytes = 0;\r
- return EFI_BAD_BUFFER_SIZE;\r
- }\r
- \r
- if (Offset > FvbDevice->LbaCache[LbaIndex].Length) {\r
- //\r
- // all exceed boundry, read nothing.\r
- //\r
- *NumBytes = 0;\r
- return EFI_BAD_BUFFER_SIZE;\r
- }\r
- \r
- NumOfBytesRead = *NumBytes;\r
- if (Offset + NumOfBytesRead > FvbDevice->LbaCache[LbaIndex].Length) {\r
- //\r
- // partial exceed boundry, read data from current postion to end.\r
- //\r
- NumOfBytesRead = FvbDevice->LbaCache[LbaIndex].Length - Offset;\r
- }\r
- \r
- LbaStart = FvbDevice->LbaCache[LbaIndex].Base;\r
- FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)((UINTN)FvbDevice->BaseAddress);\r
- LbaOffset = (UINT8 *)FwVolHeader + LbaStart + Offset;\r
-\r
- //\r
- // Perform read operation\r
- //\r
- CopyMem (Buffer, LbaOffset, NumOfBytesRead);\r
- \r
- if (NumOfBytesRead == *NumBytes) {\r
- return EFI_SUCCESS;\r
- }\r
- \r
- *NumBytes = NumOfBytesRead;\r
- return EFI_BAD_BUFFER_SIZE;\r
-}\r
- \r
-\r
-EFI_STATUS\r
-EFIAPI\r
-FwVolBlockWriteBlock (\r
- IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
- IN EFI_LBA Lba,\r
- IN UINTN Offset,\r
- IN OUT UINTN *NumBytes,\r
- IN UINT8 *Buffer\r
- )\r
-/*++\r
-\r
-Routine Description:\r
- Writes the specified number of bytes from the input buffer to the block.\r
-\r
-Arguments:\r
- This - Indicates the calling context.\r
- Lba - The starting logical block index to write to.\r
- Offset - Offset into the block at which to begin writing.\r
- NumBytes - Pointer to a UINT32. At entry, *NumBytes contains the\r
- total size of the buffer. At exit, *NumBytes contains the\r
- total number of bytes actually written.\r
- Buffer - Pinter to a caller-allocated buffer that contains the source\r
- for the write. \r
-\r
-Returns: \r
- EFI_SUCCESS - The firmware volume was written successfully.\r
- EFI_BAD_BUFFER_SIZE - The write was attempted across an LBA boundary. On output,\r
- NumBytes contains the total number of bytes actually written.\r
- EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state.\r
- EFI_DEVICE_ERROR - The block device is malfunctioning and could not be written.\r
- EFI_UNSUPPORTED - Not supported.\r
---*/\r
-{\r
- return EFI_UNSUPPORTED;\r
-}\r
- \r
-\r
-EFI_STATUS\r
-EFIAPI\r
-FwVolBlockGetPhysicalAddress (\r
- IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
- OUT EFI_PHYSICAL_ADDRESS *Address\r
- )\r
-/*++\r
-\r
-Routine Description:\r
- Get Fvb's base address.\r
-\r
-Arguments:\r
- This - Indicates the calling context.\r
- Address - Fvb device base address.\r
-\r
-Returns: \r
- EFI_SUCCESS - Successfully got Fvb's base address.\r
- EFI_UNSUPPORTED - Not supported.\r
---*/\r
-{\r
- EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
- \r
- FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
- \r
- if (FvbDevice->FvbAttributes & EFI_FVB_MEMORY_MAPPED) {\r
- *Address = FvbDevice->BaseAddress;\r
- return EFI_SUCCESS;\r
- }\r
- \r
- return EFI_UNSUPPORTED;\r
-}\r
-\r
-\r
-EFI_STATUS\r
-EFIAPI\r
-FwVolBlockGetBlockSize (\r
- IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
- IN EFI_LBA Lba,\r
- OUT UINTN *BlockSize,\r
- OUT UINTN *NumberOfBlocks\r
- )\r
-/*++\r
-\r
-Routine Description:\r
- Retrieves the size in bytes of a specific block within a firmware volume.\r
-\r
-Arguments:\r
- This - Indicates the calling context.\r
- Lba - Indicates the block for which to return the size.\r
- BlockSize - Pointer to a caller-allocated UINTN in which the size of the\r
- block is returned.\r
- NumberOfBlocks - Pointer to a caller-allocated UINTN in which the number of\r
- consecutive blocks starting with Lba is returned. All blocks\r
- in this range have a size of BlockSize. \r
-Returns:\r
- EFI_SUCCESS - The firmware volume base address is returned.\r
- EFI_INVALID_PARAMETER - The requested LBA is out of range.\r
---*/\r
-{\r
- UINTN TotalBlocks;\r
- EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
- EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry;\r
- EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
- \r
- FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
- \r
- //\r
- // Do parameter checking\r
- //\r
- if (Lba >= FvbDevice->NumBlocks) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
- \r
- FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)((UINTN)FvbDevice->BaseAddress);\r
- \r
- PtrBlockMapEntry = FwVolHeader->FvBlockMap;\r
- \r
- //\r
- // Search the block map for the given block\r
- //\r
- TotalBlocks = 0;\r
- while ((PtrBlockMapEntry->NumBlocks != 0) || (PtrBlockMapEntry->BlockLength !=0 )) {\r
- TotalBlocks += PtrBlockMapEntry->NumBlocks;\r
- if (Lba < TotalBlocks) {\r
- //\r
- // We find the range\r
- //\r
- break;\r
- }\r
- \r
- PtrBlockMapEntry++;\r
- }\r
- \r
- *BlockSize = PtrBlockMapEntry->BlockLength;\r
- *NumberOfBlocks = TotalBlocks - (UINTN)Lba;\r
- \r
- return EFI_SUCCESS;\r
-}\r
-\r
-\r
-EFI_STATUS\r
-ProduceFVBProtocolOnBuffer (\r
- IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
- IN UINT64 Length,\r
- IN EFI_HANDLE ParentHandle,\r
- OUT EFI_HANDLE *FvProtocol OPTIONAL\r
- )\r
-/*++\r
-\r
-Routine Description:\r
- This routine produces a firmware volume block protocol on a given\r
- buffer. \r
-\r
-Arguments:\r
- BaseAddress - base address of the firmware volume image\r
- Length - length of the firmware volume image\r
- ParentHandle - handle of parent firmware volume, if this\r
- image came from an FV image file in another\r
- firmware volume (ala capsules)\r
- FvProtocol - Firmware volume block protocol produced.\r
- \r
-Returns:\r
- EFI_VOLUME_CORRUPTED - Volume corrupted.\r
- EFI_OUT_OF_RESOURCES - No enough buffer to be allocated.\r
- EFI_SUCCESS - Successfully produced a FVB protocol on given buffer.\r
- \r
---*/\r
-{\r
- EFI_STATUS Status;\r
- EFI_FW_VOL_BLOCK_DEVICE *FvbDev;\r
- EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
- UINTN BlockIndex;\r
- UINTN BlockIndex2;\r
- UINTN LinearOffset;\r
- EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry;\r
-\r
- FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)BaseAddress;\r
- //\r
- // Validate FV Header, if not as expected, return\r
- //\r
- if (FwVolHeader->Signature != EFI_FVH_SIGNATURE) {\r
- return EFI_VOLUME_CORRUPTED;\r
- }\r
- //\r
- // Allocate EFI_FW_VOL_BLOCK_DEVICE \r
- //\r
- FvbDev = CoreAllocateCopyPool (sizeof (EFI_FW_VOL_BLOCK_DEVICE), &mFwVolBlock);\r
- if (FvbDev == NULL) {\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
-\r
- FvbDev->BaseAddress = BaseAddress;\r
- FvbDev->FvbAttributes = FwVolHeader->Attributes;\r
- FvbDev->FwVolBlockInstance.ParentHandle = ParentHandle;\r
-\r
- //\r
- // Init the block caching fields of the device\r
- // First, count the number of blocks\r
- //\r
- FvbDev->NumBlocks = 0;\r
- for (PtrBlockMapEntry = FwVolHeader->FvBlockMap;\r
- PtrBlockMapEntry->NumBlocks != 0;\r
- PtrBlockMapEntry++) {\r
- FvbDev->NumBlocks += PtrBlockMapEntry->NumBlocks;\r
- }\r
- //\r
- // Second, allocate the cache\r
- //\r
- FvbDev->LbaCache = CoreAllocateBootServicesPool (FvbDev->NumBlocks * sizeof (LBA_CACHE));\r
- if (FvbDev->LbaCache == NULL) {\r
- CoreFreePool (FvbDev);\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
- //\r
- // Last, fill in the cache with the linear address of the blocks\r
- //\r
- BlockIndex = 0;\r
- LinearOffset = 0;\r
- for (PtrBlockMapEntry = FwVolHeader->FvBlockMap;\r
- PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {\r
- for (BlockIndex2 = 0; BlockIndex2 < PtrBlockMapEntry->NumBlocks; BlockIndex2++) {\r
- FvbDev->LbaCache[BlockIndex].Base = LinearOffset;\r
- FvbDev->LbaCache[BlockIndex].Length = PtrBlockMapEntry->BlockLength;\r
- LinearOffset += PtrBlockMapEntry->BlockLength;\r
- BlockIndex++;\r
- }\r
- }\r
-\r
- //\r
- // Set up the devicepath\r
- //\r
- FvbDev->DevicePath.MemMapDevPath.StartingAddress = BaseAddress;\r
- FvbDev->DevicePath.MemMapDevPath.EndingAddress = BaseAddress + FwVolHeader->FvLength - 1;\r
-\r
- //\r
- //\r
- // Attach FvVolBlock Protocol to new handle\r
- //\r
- Status = CoreInstallMultipleProtocolInterfaces (\r
- &FvbDev->Handle,\r
- &gEfiFirmwareVolumeBlockProtocolGuid, &FvbDev->FwVolBlockInstance,\r
- &gEfiDevicePathProtocolGuid, &FvbDev->DevicePath,\r
- &gEfiFirmwareVolumeDispatchProtocolGuid, NULL,\r
- NULL\r
- );\r
-\r
- //\r
- // If they want the handle back, set it.\r
- //\r
- if (FvProtocol != NULL) {\r
- *FvProtocol = FvbDev->Handle;\r
- }\r
-\r
- return Status;\r
-}\r
-\r
-\r
-EFI_STATUS\r
-EFIAPI\r
-FwVolBlockDriverInit (\r
- IN EFI_HANDLE ImageHandle,\r
- IN EFI_SYSTEM_TABLE *SystemTable\r
- )\r
-/*++\r
-\r
-Routine Description:\r
- This routine is the driver initialization entry point. It initializes the\r
- libraries, consumes FV hobs and NT_NON_MM_FV environment variable and\r
- produces instances of FW_VOL_BLOCK_PROTOCOL as appropriate.\r
-Arguments:\r
- ImageHandle - The image handle.\r
- SystemTable - The system table.\r
-Returns:\r
- EFI_SUCCESS - Successfully initialized firmware volume block driver.\r
---*/\r
-{\r
- EFI_PEI_HOB_POINTERS FvHob;\r
- //\r
- // Core Needs Firmware Volumes to function\r
- //\r
- FvHob.Raw = GetHobList ();\r
- while ((FvHob.Raw = GetNextHob (EFI_HOB_TYPE_FV, FvHob.Raw)) != NULL) {\r
- //\r
- // Produce an FVB protocol for it\r
- //\r
- ProduceFVBProtocolOnBuffer (FvHob.FirmwareVolume->BaseAddress, FvHob.FirmwareVolume->Length, NULL, NULL); \r
- FvHob.Raw = GET_NEXT_HOB (FvHob);\r
- }\r
- return EFI_SUCCESS;\r
-}\r
-\r
-\r
-EFI_STATUS\r
-CoreProcessFirmwareVolume (\r
- IN VOID *FvHeader,\r
- IN UINTN Size, \r
- OUT EFI_HANDLE *FVProtocolHandle\r
- )\r
-/*++\r
-\r
-Routine Description:\r
- This DXE service routine is used to process a firmware volume. In\r
- particular, it can be called by BDS to process a single firmware\r
- volume found in a capsule. \r
-\r
-Arguments:\r
- FvHeader - pointer to a firmware volume header\r
- Size - the size of the buffer pointed to by FvHeader\r
- FVProtocolHandle - the handle on which a firmware volume protocol\r
- was produced for the firmware volume passed in.\r
-\r
-Returns:\r
- EFI_OUT_OF_RESOURCES - if an FVB could not be produced due to lack of \r
- system resources\r
- EFI_VOLUME_CORRUPTED - if the volume was corrupted\r
- EFI_SUCCESS - a firmware volume protocol was produced for the\r
- firmware volume\r
-\r
---*/\r
-{\r
- VOID *Ptr;\r
- EFI_STATUS Status;\r
-\r
- *FVProtocolHandle = NULL;\r
- Status = ProduceFVBProtocolOnBuffer ( \r
- (EFI_PHYSICAL_ADDRESS) (UINTN) FvHeader, \r
- (UINT64)Size, \r
- NULL, \r
- FVProtocolHandle\r
- );\r
- //\r
- // Since in our implementation we use register-protocol-notify to put a\r
- // FV protocol on the FVB protocol handle, we can't directly verify that\r
- // the FV protocol was produced. Therefore here we will check the handle\r
- // and make sure an FV protocol is on it. This indicates that all went \r
- // well. Otherwise we have to assume that the volume was corrupted \r
- // somehow.\r
- //\r
- if (!EFI_ERROR(Status)) {\r
- Ptr = NULL;\r
- Status = CoreHandleProtocol (*FVProtocolHandle, &gEfiFirmwareVolumeProtocolGuid, (VOID **)&Ptr);\r
- if (EFI_ERROR(Status) || (Ptr == NULL)) {\r
- return EFI_VOLUME_CORRUPTED;\r
- }\r
- return EFI_SUCCESS;\r
- }\r
- return Status;\r
-}\r
-\r
-\r