+++ /dev/null
-/** @file\r
-\r
- Implement the Firmware Volume Block (FVB) services based on SMM FVB\r
- module and install FVB protocol.\r
-\r
-Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved. <BR>\r
- \r\r
- SPDX-License-Identifier: BSD-2-Clause-Patent\r
-\r
- \r\r
-\r
-**/\r
-\r
-#include "FvbSmmDxe.h"\r
-\r
-EFI_HANDLE mHandle = NULL;\r
-EFI_SMM_COMMUNICATION_PROTOCOL *mSmmCommunication = NULL;\r
-\r
-//\r
-// Template structure used when installing FVB protocol.\r
-//\r
-EFI_FVB_DEVICE mFvbDeviceTemplate = {\r
- FVB_DEVICE_SIGNATURE,\r
- NULL,\r
- {\r
- FvbGetAttributes,\r
- FvbSetAttributes,\r
- FvbGetPhysicalAddress,\r
- FvbGetBlockSize,\r
- FvbRead,\r
- FvbWrite,\r
- FvbEraseBlocks,\r
- NULL\r
- },\r
- NULL\r
-};\r
-\r
-FV_MEMMAP_DEVICE_PATH mFvMemmapDevicePathTemplate = {\r
- {\r
- {\r
- HARDWARE_DEVICE_PATH,\r
- HW_MEMMAP_DP,\r
- {\r
- (UINT8)(sizeof (MEMMAP_DEVICE_PATH)),\r
- (UINT8)(sizeof (MEMMAP_DEVICE_PATH) >> 8)\r
- }\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
- {\r
- END_DEVICE_PATH_LENGTH,\r
- 0\r
- }\r
- }\r
-};\r
-\r
-FV_PIWG_DEVICE_PATH mFvPIWGDevicePathTemplate = {\r
- {\r
- {\r
- MEDIA_DEVICE_PATH,\r
- MEDIA_PIWG_FW_VOL_DP,\r
- {\r
- (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH)),\r
- (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH) >> 8)\r
- }\r
- },\r
- { 0 }\r
- },\r
- {\r
- END_DEVICE_PATH_TYPE,\r
- END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
- {\r
- END_DEVICE_PATH_LENGTH,\r
- 0\r
- }\r
- }\r
-};\r
-\r
-/**\r
- Initialize the communicate buffer using DataSize and Function.\r
-\r
- The communicate size is: SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE +\r
- DataSize.\r
-\r
- @param[out] CommunicateBuffer The communicate buffer. Caller should free it after use.\r
- @param[out] DataPtr Points to the data in the communicate buffer. Caller should not free it.\r
- @param[in] DataSize The payload size.\r
- @param[in] Function The function number used to initialize the communicate header.\r
-\r
- @retval EFI_INVALID_PARAMETER The data size is too big.\r
- @retval EFI_SUCCESS Find the specified variable.\r
-\r
-**/\r
-EFI_STATUS\r
-InitCommunicateBuffer (\r
- OUT VOID **CommunicateBuffer,\r
- OUT VOID **DataPtr,\r
- IN UINTN DataSize,\r
- IN UINTN Function\r
- )\r
-{\r
- EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;\r
- SMM_FVB_COMMUNICATE_FUNCTION_HEADER *SmmFvbFunctionHeader;\r
-\r
- //\r
- // The whole buffer size: SMM_COMMUNICATE_HEADER_SIZE + SMM_FVB_COMMUNICATE_HEADER_SIZE + DataSize.\r
- //\r
- SmmCommunicateHeader = AllocatePool (DataSize + SMM_COMMUNICATE_HEADER_SIZE + SMM_FVB_COMMUNICATE_HEADER_SIZE);\r
- ASSERT (SmmCommunicateHeader != NULL);\r
-\r
- //\r
- // Prepare data buffer.\r
- //\r
- CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmFirmwareVolumeBlockProtocolGuid);\r
- SmmCommunicateHeader->MessageLength = DataSize + SMM_FVB_COMMUNICATE_HEADER_SIZE;\r
-\r
- SmmFvbFunctionHeader = (SMM_FVB_COMMUNICATE_FUNCTION_HEADER *) SmmCommunicateHeader->Data;\r
- SmmFvbFunctionHeader->Function = Function;\r
-\r
- *CommunicateBuffer = SmmCommunicateHeader;\r
- *DataPtr = SmmFvbFunctionHeader->Data;\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-\r
-/**\r
- Send the data in communicate buffer to SMM.\r
-\r
- @param[out] SmmCommunicateHeader The communicate buffer.\r
- @param[in] DataSize The payload size.\r
-\r
-**/\r
-EFI_STATUS\r
-SendCommunicateBuffer (\r
- IN EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader,\r
- IN UINTN DataSize\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINTN CommSize;\r
- SMM_FVB_COMMUNICATE_FUNCTION_HEADER *SmmFvbFunctionHeader;\r
-\r
- CommSize = DataSize + SMM_COMMUNICATE_HEADER_SIZE + SMM_FVB_COMMUNICATE_HEADER_SIZE;\r
- Status = mSmmCommunication->Communicate (\r
- mSmmCommunication,\r
- SmmCommunicateHeader,\r
- &CommSize\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- SmmFvbFunctionHeader = (SMM_FVB_COMMUNICATE_FUNCTION_HEADER *) SmmCommunicateHeader->Data;\r
- return SmmFvbFunctionHeader->ReturnStatus;\r
-}\r
-\r
-/**\r
- This function retrieves the attributes and current settings of the block.\r
-\r
- @param[in] This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.\r
-\r
- @param[out] Attributes Pointer to EFI_FVB_ATTRIBUTES_2 in which the attributes\r
- and current settings are returned. Type EFI_FVB_ATTRIBUTES_2\r
- is defined in EFI_FIRMWARE_VOLUME_HEADER.\r
-\r
- @retval EFI_SUCCESS The firmware volume attributes were returned.\r
- @retval EFI_INVALID_PARAMETER Attributes is NULL.\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-FvbGetAttributes (\r
- IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
- OUT EFI_FVB_ATTRIBUTES_2 *Attributes\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINTN PayloadSize;\r
- EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;\r
- SMM_FVB_ATTRIBUTES_HEADER *SmmFvbAttributesHeader;\r
- EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb;\r
- EFI_FVB_DEVICE *FvbDevice;\r
-\r
- if (Attributes == NULL) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
- SmmFvb = FvbDevice->SmmFvbInstance;\r
-\r
- //\r
- // Initialize the communicate buffer.\r
- //\r
- PayloadSize = sizeof (SMM_FVB_ATTRIBUTES_HEADER);\r
- Status = InitCommunicateBuffer (\r
- (VOID **)&SmmCommunicateHeader,\r
- (VOID **)&SmmFvbAttributesHeader,\r
- PayloadSize,\r
- EFI_FUNCTION_GET_ATTRIBUTES\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- SmmFvbAttributesHeader->SmmFvb = SmmFvb;\r
- SmmFvbAttributesHeader->Attributes = 0;\r
-\r
- //\r
- // Send data to SMM.\r
- //\r
- Status = SendCommunicateBuffer (SmmCommunicateHeader, PayloadSize);\r
-\r
- //\r
- // Get data from SMM.\r
- //\r
- *Attributes = SmmFvbAttributesHeader->Attributes;\r
- FreePool (SmmCommunicateHeader);\r
-\r
- return Status;\r
-}\r
-\r
-\r
-/**\r
- Sets Volume attributes. No polarity translations are done.\r
-\r
- @param[in] This Calling context.\r
- @param[out] Attributes Output buffer which contains attributes.\r
-\r
- @retval EFI_SUCCESS Set the Attributes successfully.\r
- @retval EFI_INVALID_PARAMETER Attributes is NULL.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-FvbSetAttributes (\r
- IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
- IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINTN PayloadSize;\r
- EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;\r
- SMM_FVB_ATTRIBUTES_HEADER *SmmFvbAttributesHeader;\r
- EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb;\r
- EFI_FVB_DEVICE *FvbDevice;\r
-\r
- if (Attributes == NULL) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
- SmmFvb = FvbDevice->SmmFvbInstance;\r
-\r
- //\r
- // Initialize the communicate buffer.\r
- //\r
- PayloadSize = sizeof (SMM_FVB_ATTRIBUTES_HEADER);\r
- Status = InitCommunicateBuffer (\r
- (VOID **)&SmmCommunicateHeader,\r
- (VOID **)&SmmFvbAttributesHeader,\r
- PayloadSize,\r
- EFI_FUNCTION_SET_ATTRIBUTES\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- SmmFvbAttributesHeader->SmmFvb = SmmFvb;\r
- SmmFvbAttributesHeader->Attributes = *Attributes;\r
-\r
- //\r
- // Send data to SMM.\r
- //\r
- Status = SendCommunicateBuffer (SmmCommunicateHeader, PayloadSize);\r
-\r
- //\r
- // Get data from SMM.\r
- //\r
- *Attributes = SmmFvbAttributesHeader->Attributes;\r
- FreePool (SmmCommunicateHeader);\r
-\r
- return Status;\r
-}\r
-\r
-\r
-/**\r
- Retrieves the physical address of the FVB instance.\r
-\r
- @param[in] SmmFvb A pointer to EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL.\r
- @param[out] Address Output buffer containing the address.\r
-\r
- @retval EFI_SUCCESS Get the address successfully.\r
- @retval Others Failed to get address.\r
-\r
-**/\r
-EFI_STATUS\r
-GetPhysicalAddress (\r
- IN EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb,\r
- OUT EFI_PHYSICAL_ADDRESS *Address\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINTN PayloadSize;\r
- EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;\r
- SMM_FVB_PHYSICAL_ADDRESS_HEADER *SmmFvbPhysicalAddressHeader;\r
-\r
- //\r
- // Initialize the communicate buffer.\r
- //\r
- PayloadSize = sizeof (SMM_FVB_PHYSICAL_ADDRESS_HEADER);\r
- Status = InitCommunicateBuffer (\r
- (VOID **)&SmmCommunicateHeader,\r
- (VOID **)&SmmFvbPhysicalAddressHeader,\r
- PayloadSize,\r
- EFI_FUNCTION_GET_PHYSICAL_ADDRESS\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- SmmFvbPhysicalAddressHeader->SmmFvb = SmmFvb;\r
- SmmFvbPhysicalAddressHeader->Address = 0;\r
-\r
- //\r
- // Send data to SMM.\r
- //\r
- Status = SendCommunicateBuffer (SmmCommunicateHeader, PayloadSize);\r
-\r
- //\r
- // Get data from SMM.\r
- //\r
- *Address = SmmFvbPhysicalAddressHeader->Address;\r
- FreePool (SmmCommunicateHeader);\r
-\r
- return Status;\r
-}\r
-\r
-\r
-/**\r
- Retrieves the physical address of the FVB instance.\r
-\r
- @param[in] This A pointer to EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL.\r
- @param[out] Address Output buffer containing the address.\r
-\r
- @retval EFI_SUCCESS Get the address successfully.\r
- @retval Others Failed to get the address.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-FvbGetPhysicalAddress (\r
- IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
- OUT EFI_PHYSICAL_ADDRESS *Address\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb;\r
- EFI_FVB_DEVICE *FvbDevice;\r
-\r
- if (Address == NULL) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
- SmmFvb = FvbDevice->SmmFvbInstance;\r
-\r
- Status = GetPhysicalAddress (SmmFvb, Address);\r
-\r
- return Status;\r
-}\r
-\r
-\r
-/**\r
- Retrieve the size of a logical block.\r
-\r
- @param[in] This Calling context.\r
- @param[in] Lba Indicates which block to return the size for.\r
- @param[out] BlockSize A pointer to a caller allocated UINTN in which\r
- the size of the block is returned.\r
- @param[out] NumOfBlocks A pointer to a caller allocated UINTN in which the\r
- number of consecutive blocks starting with Lba is\r
- returned. All blocks in this range have a size of\r
- BlockSize.\r
-\r
- @retval EFI_SUCCESS Get BlockSize and NumOfBlocks successfully.\r
- @retval EFI_INVALID_PARAMETER BlockSize or NumOfBlocks are NULL.\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-FvbGetBlockSize (\r
- IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
- IN EFI_LBA Lba,\r
- OUT UINTN *BlockSize,\r
- OUT UINTN *NumOfBlocks\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINTN PayloadSize;\r
- EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;\r
- SMM_FVB_BLOCK_SIZE_HEADER *SmmFvbBlockSizeHeader;\r
- EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb;\r
- EFI_FVB_DEVICE *FvbDevice;\r
-\r
- if ((BlockSize == NULL) || (NumOfBlocks == NULL)) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
- SmmFvb = FvbDevice->SmmFvbInstance;\r
-\r
- //\r
- // Initialize the communicate buffer.\r
- //\r
- PayloadSize = sizeof (SMM_FVB_BLOCK_SIZE_HEADER);\r
- Status = InitCommunicateBuffer (\r
- (VOID **)&SmmCommunicateHeader,\r
- (VOID **)&SmmFvbBlockSizeHeader,\r
- PayloadSize,\r
- EFI_FUNCTION_GET_BLOCK_SIZE\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- SmmFvbBlockSizeHeader->SmmFvb = SmmFvb;\r
- SmmFvbBlockSizeHeader->Lba = Lba;\r
-\r
- //\r
- // Send data to SMM.\r
- //\r
- Status = SendCommunicateBuffer (SmmCommunicateHeader, PayloadSize);\r
-\r
- //\r
- // Get data from SMM.\r
- //\r
- *BlockSize = SmmFvbBlockSizeHeader->BlockSize;\r
- *NumOfBlocks = SmmFvbBlockSizeHeader->NumOfBlocks;\r
- FreePool (SmmCommunicateHeader);\r
-\r
- return Status;\r
-}\r
-\r
-\r
-/**\r
- Reads data beginning at Lba:Offset from FV. The Read terminates either\r
- when *NumBytes of data have been read, or when a block boundary is\r
- reached. *NumBytes is updated to reflect the actual number of bytes\r
- written. The write opertion does not include erase. This routine will\r
- attempt to write only the specified bytes. If the writes do not stick,\r
- it will return an error.\r
-\r
- @param[in] This Calling context\r
- @param[in] Lba Block in which to begin write\r
- @param[in] Offset Offset in the block at which to begin write\r
- @param[in,out] NumBytes On input, indicates the requested write size. On\r
- output, indicates the actual number of bytes written\r
- @param[in] Buffer Buffer containing source data for the write.\r
-\r
- @retval EFI_SUCCESS The firmware volume was read successfully and\r
- contents are in Buffer.\r
- @retval EFI_BAD_BUFFER_SIZE Read attempted across a LBA boundary. On output,\r
- NumBytes contains the total number of bytes returned\r
- in Buffer.\r
- @retval EFI_ACCESS_DENIED The firmware volume is in the ReadDisabled state\r
- @retval EFI_DEVICE_ERROR The block device is not functioning correctly and\r
- could not be read.\r
- @retval EFI_INVALID_PARAMETER NumBytes or Buffer are NULL.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-FvbRead (\r
- IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
- IN EFI_LBA Lba,\r
- IN UINTN Offset,\r
- IN OUT UINTN *NumBytes,\r
- OUT UINT8 *Buffer\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINTN PayloadSize;\r
- EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;\r
- SMM_FVB_READ_WRITE_HEADER *SmmFvbReadWriteHeader;\r
- EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb;\r
- EFI_FVB_DEVICE *FvbDevice;\r
-\r
- if ((NumBytes == NULL) || (Buffer == NULL)) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
- SmmFvb = FvbDevice->SmmFvbInstance;\r
-\r
- //\r
- // Initialize the communicate buffer.\r
- //\r
- PayloadSize = sizeof (SMM_FVB_READ_WRITE_HEADER) + *NumBytes;\r
- Status = InitCommunicateBuffer (\r
- (VOID **)&SmmCommunicateHeader,\r
- (VOID **)&SmmFvbReadWriteHeader,\r
- PayloadSize, EFI_FUNCTION_READ\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- SmmFvbReadWriteHeader->SmmFvb = SmmFvb;\r
- SmmFvbReadWriteHeader->Lba = Lba;\r
- SmmFvbReadWriteHeader->Offset = Offset;\r
- SmmFvbReadWriteHeader->NumBytes = *NumBytes;\r
-\r
- //\r
- // Send data to SMM.\r
- //\r
- Status = SendCommunicateBuffer (SmmCommunicateHeader, PayloadSize);\r
-\r
- //\r
- // Get data from SMM.\r
- //\r
- *NumBytes = SmmFvbReadWriteHeader->NumBytes;\r
- if (!EFI_ERROR (Status)) {\r
- CopyMem (Buffer, (UINT8 *)(SmmFvbReadWriteHeader + 1), *NumBytes);\r
- }\r
- FreePool (SmmCommunicateHeader);\r
-\r
- return Status;\r
-}\r
-\r
-\r
-/**\r
- Writes data beginning at Lba:Offset from FV. The write terminates either\r
- when *NumBytes of data have been written, or when a block boundary is\r
- reached. *NumBytes is updated to reflect the actual number of bytes\r
- written. The write opertion does not include erase. This routine will\r
- attempt to write only the specified bytes. If the writes do not stick,\r
- it will return an error.\r
-\r
- @param[in] This Calling context.\r
- @param[in] Lba Block in which to begin write.\r
- @param[in] Offset Offset in the block at which to begin write.\r
- @param[in,out] NumBytes On input, indicates the requested write size. On\r
- output, indicates the actual number of bytes written.\r
- @param[in] Buffer Buffer containing source data for the write.\r
-\r
- @retval EFI_SUCCESS The firmware volume was written successfully.\r
- @retval EFI_BAD_BUFFER_SIZE Write attempted across a LBA boundary. On output,\r
- NumBytes contains the total number of bytes\r
- actually written.\r
- @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state.\r
- @retval EFI_DEVICE_ERROR The block device is not functioning correctly and\r
- could not be written.\r
- @retval EFI_INVALID_PARAMETER NumBytes or Buffer are NULL.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-FvbWrite (\r
- IN CONST 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
- EFI_STATUS Status;\r
- UINTN PayloadSize;\r
- EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;\r
- SMM_FVB_READ_WRITE_HEADER *SmmFvbReadWriteHeader;\r
- EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb;\r
- EFI_FVB_DEVICE *FvbDevice;\r
-\r
- if ((NumBytes == NULL) || (Buffer == NULL)) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
- SmmFvb = FvbDevice->SmmFvbInstance;\r
-\r
- //\r
- // Initialize the communicate buffer.\r
- //\r
- PayloadSize = sizeof (SMM_FVB_READ_WRITE_HEADER) + *NumBytes;\r
- Status = InitCommunicateBuffer (\r
- (VOID **)&SmmCommunicateHeader,\r
- (VOID **)&SmmFvbReadWriteHeader,\r
- PayloadSize,\r
- EFI_FUNCTION_WRITE\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- SmmFvbReadWriteHeader->SmmFvb = SmmFvb;\r
- SmmFvbReadWriteHeader->Lba = Lba;\r
- SmmFvbReadWriteHeader->Offset = Offset;\r
- SmmFvbReadWriteHeader->NumBytes = *NumBytes;\r
- CopyMem ((UINT8 *)(SmmFvbReadWriteHeader + 1), Buffer, *NumBytes);\r
-\r
- //\r
- // Send data to SMM.\r
- //\r
- Status = SendCommunicateBuffer (SmmCommunicateHeader, PayloadSize);\r
-\r
- //\r
- // Get data from SMM.\r
- //\r
- *NumBytes = SmmFvbReadWriteHeader->NumBytes;\r
- FreePool (SmmCommunicateHeader);\r
-\r
- return Status;\r
-}\r
-\r
-\r
-/**\r
- The EraseBlock() function erases NumOfLba blocks started from StartingLba.\r
-\r
- @param[in] This Calling context.\r
- @param[in] StartingLba Starting LBA followed to erase.\r
- @param[in] NumOfLba Number of block to erase.\r
-\r
- @retval EFI_SUCCESS The erase request was successfully completed.\r
- @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state.\r
- @retval EFI_DEVICE_ERROR The block device is not functioning correctly and\r
- could not be written. Firmware device may have been\r
- partially erased.\r
-\r
-**/\r
-EFI_STATUS\r
-EraseBlock (\r
- IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
- IN EFI_LBA StartingLba,\r
- IN UINTN NumOfLba\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINTN PayloadSize;\r
- EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;\r
- SMM_FVB_BLOCKS_HEADER *SmmFvbBlocksHeader;\r
- EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb;\r
- EFI_FVB_DEVICE *FvbDevice;\r
-\r
- FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
- SmmFvb = FvbDevice->SmmFvbInstance;\r
-\r
- //\r
- // Initialize the communicate buffer.\r
- //\r
- PayloadSize = sizeof (SMM_FVB_BLOCKS_HEADER);\r
- Status = InitCommunicateBuffer (\r
- (VOID **)&SmmCommunicateHeader,\r
- (VOID **)&SmmFvbBlocksHeader,\r
- PayloadSize,\r
- EFI_FUNCTION_ERASE_BLOCKS\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- SmmFvbBlocksHeader->SmmFvb = SmmFvb;\r
- SmmFvbBlocksHeader->StartLba = StartingLba;\r
- SmmFvbBlocksHeader->NumOfLba = NumOfLba;\r
-\r
- //\r
- // Send data to SMM.\r
- //\r
- Status = SendCommunicateBuffer (SmmCommunicateHeader, PayloadSize);\r
-\r
- //\r
- // Get data from SMM.\r
- //\r
- FreePool (SmmCommunicateHeader);\r
-\r
- return Status;\r
-}\r
-\r
-\r
-/**\r
- The EraseBlocks() 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
- @param[in] This Calling context/\r
- @param[in] ... Starting LBA followed by Number of Lba to erase.\r
- a -1 to terminate the list.\r
-/\r
- @retval EFI_SUCCESS The erase request was successfully completed\r
- @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state/\r
- @retval EFI_DEVICE_ERROR The block device is not functioning correctly and\r
- could not be written. Firmware device may have been\r
- partially erased/\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-FvbEraseBlocks (\r
- IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
- ...\r
- )\r
-{\r
- EFI_STATUS Status;\r
- VA_LIST Marker;\r
- EFI_LBA StartingLba;\r
- UINTN NumOfLba;\r
-\r
- Status = EFI_SUCCESS;\r
-\r
- //\r
- // Check the parameter.\r
- //\r
- VA_START (Marker, This);\r
- do {\r
- StartingLba = VA_ARG (Marker, EFI_LBA);\r
- if (StartingLba == EFI_LBA_LIST_TERMINATOR ) {\r
- break;\r
- }\r
-\r
- NumOfLba = VA_ARG (Marker, UINTN);\r
- if (NumOfLba == 0) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- } while ( 1 );\r
- VA_END (Marker);\r
-\r
- //\r
- // Erase the blocks.\r
- //\r
- VA_START (Marker, This);\r
- do {\r
- StartingLba = VA_ARG (Marker, EFI_LBA);\r
- if (StartingLba == EFI_LBA_LIST_TERMINATOR ) {\r
- break;\r
- }\r
- NumOfLba = VA_ARG (Marker, UINTN);\r
- Status = EraseBlock (This, StartingLba, NumOfLba);\r
- if (EFI_ERROR (Status)) {\r
- break;\r
- }\r
- } while ( 1 );\r
- VA_END (Marker);\r
-\r
- return Status;\r
-}\r
-\r
-\r
-/**\r
- Install the FVB protocol which based on SMM FVB protocol.\r
-\r
- @param[in] SmmFvb The SMM FVB protocol.\r
-\r
-**/\r
-VOID\r
-InstallFvb (\r
- IN EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_HANDLE FvbHandle;\r
- EFI_FVB_DEVICE *FvbDevice;\r
- EFI_FIRMWARE_VOLUME_HEADER *VolumeHeader;\r
- EFI_PHYSICAL_ADDRESS Address;\r
- EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *OldFvbInterface;\r
-\r
- FvbDevice = AllocateRuntimeCopyPool (sizeof (EFI_FVB_DEVICE), &mFvbDeviceTemplate);\r
- ASSERT (FvbDevice != NULL);\r
- FvbDevice->SmmFvbInstance = SmmFvb;\r
-\r
- Status = gBS->LocateProtocol (\r
- &gEfiSmmCommunicationProtocolGuid,\r
- NULL,\r
- (VOID **) &mSmmCommunication\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- Status = GetPhysicalAddress (SmmFvb, &Address);\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- VolumeHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN)Address;\r
-\r
- //\r
- // Set up the devicepath.\r
- //\r
- if (VolumeHeader->ExtHeaderOffset == 0) {\r
- //\r
- // FV does not contains extension header, then produce MEMMAP_DEVICE_PATH.\r
- //\r
- FvbDevice->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) AllocateRuntimeCopyPool (sizeof (FV_MEMMAP_DEVICE_PATH), &mFvMemmapDevicePathTemplate);\r
- ((FV_MEMMAP_DEVICE_PATH *) FvbDevice->DevicePath)->MemMapDevPath.StartingAddress = (UINTN)Address;\r
- ((FV_MEMMAP_DEVICE_PATH *) FvbDevice->DevicePath)->MemMapDevPath.EndingAddress = (UINTN)Address + VolumeHeader->FvLength - 1;\r
- } else {\r
- FvbDevice->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) AllocateRuntimeCopyPool (sizeof (FV_PIWG_DEVICE_PATH), &mFvPIWGDevicePathTemplate);\r
- CopyGuid (\r
- &((FV_PIWG_DEVICE_PATH *)FvbDevice->DevicePath)->FvDevPath.FvName,\r
- (GUID *)(UINTN)((UINTN)Address + VolumeHeader->ExtHeaderOffset)\r
- );\r
- }\r
-\r
- //\r
- // Find a handle with a matching device path that has supports FW Block protocol.\r
- //\r
- Status = gBS->LocateDevicePath (\r
- &gEfiFirmwareVolumeBlockProtocolGuid,\r
- &FvbDevice->DevicePath,\r
- &FvbHandle\r
- );\r
- if (EFI_ERROR (Status) ) {\r
- //\r
- // LocateDevicePath fails so install a new interface and device path.\r
- //\r
- FvbHandle = NULL;\r
- Status = gBS->InstallMultipleProtocolInterfaces (\r
- &FvbHandle,\r
- &gEfiFirmwareVolumeBlockProtocolGuid,\r
- &FvbDevice->FvbInstance,\r
- &gEfiDevicePathProtocolGuid,\r
- FvbDevice->DevicePath,\r
- NULL\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
- } else if (IsDevicePathEnd (FvbDevice->DevicePath)) {\r
- //\r
- // Device allready exists, so reinstall the FVB protocol.\r
- //\r
- Status = gBS->HandleProtocol (\r
- FvbHandle,\r
- &gEfiFirmwareVolumeBlockProtocolGuid,\r
- (VOID **) &OldFvbInterface\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- Status = gBS->ReinstallProtocolInterface (\r
- FvbHandle,\r
- &gEfiFirmwareVolumeBlockProtocolGuid,\r
- OldFvbInterface,\r
- &FvbDevice->FvbInstance\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
- } else {\r
- //\r
- // There was a FVB protocol on an End Device Path node.\r
- //\r
- ASSERT (FALSE);\r
- }\r
-}\r
-\r
-\r
-/**\r
- SMM Firmware Volume Block Protocol notification event handler.\r
-\r
- Discover NV Variable Store and install Variable Write Arch Protocol.\r
-\r
- @param[in] Event Event whose notification function is being invoked.\r
- @param[in] Context Pointer to the notification function's context.\r
-**/\r
-VOID\r
-EFIAPI\r
-SmmFvbReady (\r
- IN EFI_EVENT Event,\r
- IN VOID *Context\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_HANDLE *HandleBuffer;\r
- UINTN HandleCount;\r
- UINTN Index;\r
- EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb;\r
-\r
- //\r
- // Locate all handles of Smm Fvb protocol.\r
- //\r
- Status = gBS->LocateHandleBuffer (\r
- ByProtocol,\r
- &gEfiSmmFirmwareVolumeBlockProtocolGuid,\r
- NULL,\r
- &HandleCount,\r
- &HandleBuffer\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return ;\r
- }\r
-\r
- //\r
- // Install FVB protocol.\r
- //\r
- for (Index = 0; Index < HandleCount; Index++) {\r
- SmmFvb = NULL;\r
- Status = gBS->HandleProtocol (\r
- HandleBuffer[Index],\r
- &gEfiSmmFirmwareVolumeBlockProtocolGuid,\r
- (VOID **) &SmmFvb\r
- );\r
- if (EFI_ERROR (Status)) {\r
- break;\r
- }\r
-\r
- InstallFvb (SmmFvb);\r
- }\r
-\r
- FreePool (HandleBuffer);\r
-}\r
-\r
-\r
-/**\r
- The driver entry point for Firmware Volume Block Driver.\r
-\r
- The function does the necessary initialization work\r
- Firmware Volume Block Driver.\r
-\r
- @param[in] ImageHandle The firmware allocated handle for the UEFI image.\r
- @param[in] SystemTable A pointer to the EFI system table.\r
-\r
- @retval EFI_SUCCESS This funtion always return EFI_SUCCESS.\r
- It will ASSERT on errors.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-FvbSmmDxeInitialize (\r
- IN EFI_HANDLE ImageHandle,\r
- IN EFI_SYSTEM_TABLE *SystemTable\r
- )\r
-{\r
- VOID *SmmFvbRegistration;\r
-\r
- //\r
- // Smm FVB driver is ready.\r
- //\r
- EfiCreateProtocolNotifyEvent (\r
- &gEfiSmmFirmwareVolumeBlockProtocolGuid,\r
- TPL_CALLBACK,\r
- SmmFvbReady,\r
- NULL,\r
- &SmmFvbRegistration\r
- );\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r