| /** @file | |
| UEFI PI specification supersedes Inte's Framework Specification. | |
| EFI_FIRMWARE_VOLUME_PROTOCOL defined in Intel Framework Pkg is replaced by | |
| EFI_FIRMWARE_VOLUME2_PROTOCOL in MdePkg. | |
| This module produces FV on top of FV2. This module is used on platform when both of | |
| these two conditions are true: | |
| 1) Framework module consuming FV is present | |
| 2) And the platform only produces FV2 | |
| Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR> | |
| 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: | |
| **/ | |
| #include <PiDxe.h> | |
| #include <Protocol/FirmwareVolume2.h> | |
| #include <Protocol/FirmwareVolume.h> | |
| #include <Library/BaseLib.h> | |
| #include <Library/DebugLib.h> | |
| #include <Library/UefiBootServicesTableLib.h> | |
| #include <Library/UefiDriverEntryPoint.h> | |
| #include <Library/UefiLib.h> | |
| #include <Library/MemoryAllocationLib.h> | |
| #define FIRMWARE_VOLUME_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('f', 'v', 't', 'h') | |
| typedef struct { | |
| UINTN Signature; | |
| EFI_FIRMWARE_VOLUME_PROTOCOL FirmwareVolume; | |
| EFI_FIRMWARE_VOLUME2_PROTOCOL *FirmwareVolume2; | |
| } FIRMWARE_VOLUME_PRIVATE_DATA; | |
| #define FIRMWARE_VOLUME_PRIVATE_DATA_FROM_THIS(a) CR (a, FIRMWARE_VOLUME_PRIVATE_DATA, FirmwareVolume, FIRMWARE_VOLUME_PRIVATE_DATA_SIGNATURE) | |
| /** | |
| Convert FV attrbiutes to FV2 attributes. | |
| @param Fv2Attributes FV2 attributes. | |
| @return FV attributes. | |
| **/ | |
| FRAMEWORK_EFI_FV_ATTRIBUTES | |
| Fv2AttributesToFvAttributes ( | |
| IN EFI_FV_ATTRIBUTES Fv2Attributes | |
| ) | |
| { | |
| // | |
| // Clear those filed that is not defined in Framework FV spec and Alignment conversion. | |
| // | |
| return (Fv2Attributes & 0x1ff) | ((UINTN) EFI_FV_ALIGNMENT_2 << RShiftU64((Fv2Attributes & EFI_FV2_ALIGNMENT), 16)); | |
| } | |
| /** | |
| Retrieves attributes, insures positive polarity of attribute bits, returns | |
| resulting attributes in output parameter. | |
| @param This Calling context | |
| @param Attributes output buffer which contains attributes | |
| @retval EFI_SUCCESS The firmware volume attributes were returned. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| FvGetVolumeAttributes ( | |
| IN EFI_FIRMWARE_VOLUME_PROTOCOL *This, | |
| OUT FRAMEWORK_EFI_FV_ATTRIBUTES *Attributes | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| FIRMWARE_VOLUME_PRIVATE_DATA *Private; | |
| EFI_FIRMWARE_VOLUME2_PROTOCOL *FirmwareVolume2; | |
| Private = FIRMWARE_VOLUME_PRIVATE_DATA_FROM_THIS (This); | |
| FirmwareVolume2 = Private->FirmwareVolume2; | |
| Status = FirmwareVolume2->GetVolumeAttributes ( | |
| FirmwareVolume2, | |
| Attributes | |
| ); | |
| if (!EFI_ERROR (Status)) { | |
| *Attributes = Fv2AttributesToFvAttributes (*Attributes); | |
| } | |
| return Status; | |
| } | |
| /** | |
| Sets volume attributes. | |
| @param This Calling context | |
| @param Attributes Buffer which contains attributes | |
| @retval EFI_INVALID_PARAMETER A bit in Attributes was invalid | |
| @retval EFI_SUCCESS The requested firmware volume attributes were set | |
| and the resulting EFI_FV_ATTRIBUTES is returned in | |
| Attributes. | |
| @retval EFI_ACCESS_DENIED The Device is locked and does not permit modification. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| FvSetVolumeAttributes ( | |
| IN EFI_FIRMWARE_VOLUME_PROTOCOL *This, | |
| IN OUT FRAMEWORK_EFI_FV_ATTRIBUTES *Attributes | |
| ) | |
| { | |
| FIRMWARE_VOLUME_PRIVATE_DATA *Private; | |
| EFI_FIRMWARE_VOLUME2_PROTOCOL *FirmwareVolume2; | |
| EFI_FV_ATTRIBUTES Fv2Attributes; | |
| EFI_STATUS Status; | |
| Private = FIRMWARE_VOLUME_PRIVATE_DATA_FROM_THIS (This); | |
| FirmwareVolume2 = Private->FirmwareVolume2; | |
| Fv2Attributes = (*Attributes & 0x1ff); | |
| Status = FirmwareVolume2->SetVolumeAttributes ( | |
| FirmwareVolume2, | |
| &Fv2Attributes | |
| ); | |
| *Attributes = Fv2AttributesToFvAttributes (Fv2Attributes); | |
| return Status; | |
| } | |
| /** | |
| Read the requested file (NameGuid) and returns data in Buffer. | |
| @param This Calling context | |
| @param NameGuid Filename identifying which file to read | |
| @param Buffer Pointer to pointer to buffer in which contents of file are returned. | |
| <br> | |
| If Buffer is NULL, only type, attributes, and size are returned as | |
| there is no output buffer. | |
| <br> | |
| If Buffer != NULL and *Buffer == NULL, the output buffer is allocated | |
| from BS pool by ReadFile | |
| <br> | |
| If Buffer != NULL and *Buffer != NULL, the output buffer has been | |
| allocated by the caller and is being passed in. | |
| @param BufferSize Indicates the buffer size passed in, and on output the size | |
| required to complete the read | |
| @param FoundType Indicates the type of the file who's data is returned | |
| @param FileAttributes Indicates the attributes of the file who's data is resturned | |
| @param AuthenticationStatus Indicates the authentication status of the data | |
| @retval EFI_SUCCESS The call completed successfully | |
| @retval EFI_WARN_BUFFER_TOO_SMALL The buffer is too small to contain the requested output. | |
| The buffer is filled and the output is truncated. | |
| @retval EFI_NOT_FOUND NameGuid was not found in the firmware volume. | |
| @retval EFI_DEVICE_ERROR A hardware error occurred when attempting to access the firmware volume. | |
| @retval EFI_ACCESS_DENIED The firmware volume is configured to disallow reads. | |
| @retval EFI_OUT_OF_RESOURCES An allocation failure occurred. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| FvReadFile ( | |
| IN EFI_FIRMWARE_VOLUME_PROTOCOL *This, | |
| IN EFI_GUID *NameGuid, | |
| IN OUT VOID **Buffer, | |
| IN OUT UINTN *BufferSize, | |
| OUT EFI_FV_FILETYPE *FoundType, | |
| OUT EFI_FV_FILE_ATTRIBUTES *FileAttributes, | |
| OUT UINT32 *AuthenticationStatus | |
| ) | |
| { | |
| FIRMWARE_VOLUME_PRIVATE_DATA *Private; | |
| EFI_FIRMWARE_VOLUME2_PROTOCOL *FirmwareVolume2; | |
| EFI_STATUS Status; | |
| Private = FIRMWARE_VOLUME_PRIVATE_DATA_FROM_THIS (This); | |
| FirmwareVolume2 = Private->FirmwareVolume2; | |
| Status = FirmwareVolume2->ReadFile ( | |
| FirmwareVolume2, | |
| NameGuid, | |
| Buffer, | |
| BufferSize, | |
| FoundType, | |
| FileAttributes, | |
| AuthenticationStatus | |
| ); | |
| // | |
| // For Framework FV attrbutes, only alignment fields are valid. | |
| // | |
| *FileAttributes = *FileAttributes & EFI_FV_FILE_ATTRIB_ALIGNMENT; | |
| return Status; | |
| } | |
| /** | |
| Read the requested section from the specified file and returns data in Buffer. | |
| @param This Calling context | |
| @param NameGuid Filename identifying the file from which to read | |
| @param SectionType Indicates what section type to retrieve | |
| @param SectionInstance Indicates which instance of SectionType to retrieve | |
| @param Buffer Pointer to pointer to buffer in which contents of file are returned. | |
| <br> | |
| If Buffer is NULL, only type, attributes, and size are returned as | |
| there is no output buffer. | |
| <br> | |
| If Buffer != NULL and *Buffer == NULL, the output buffer is allocated | |
| from BS pool by ReadFile | |
| <br> | |
| If Buffer != NULL and *Buffer != NULL, the output buffer has been | |
| allocated by the caller and is being passed in. | |
| @param BufferSize Indicates the buffer size passed in, and on output the size | |
| required to complete the read | |
| @param AuthenticationStatus Indicates the authentication status of the data | |
| @retval EFI_SUCCESS The call completed successfully. | |
| @retval EFI_WARN_BUFFER_TOO_SMALL The buffer is too small to contain the requested output. | |
| The buffer is filled and the output is truncated. | |
| @retval EFI_OUT_OF_RESOURCES An allocation failure occurred. | |
| @retval EFI_NOT_FOUND Name was not found in the firmware volume. | |
| @retval EFI_DEVICE_ERROR A hardware error occurred when attempting to access the firmware volume. | |
| @retval EFI_ACCESS_DENIED The firmware volume is configured to disallow reads. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| FvReadSection ( | |
| IN EFI_FIRMWARE_VOLUME_PROTOCOL *This, | |
| IN EFI_GUID *NameGuid, | |
| IN EFI_SECTION_TYPE SectionType, | |
| IN UINTN SectionInstance, | |
| IN OUT VOID **Buffer, | |
| IN OUT UINTN *BufferSize, | |
| OUT UINT32 *AuthenticationStatus | |
| ) | |
| { | |
| FIRMWARE_VOLUME_PRIVATE_DATA *Private; | |
| EFI_FIRMWARE_VOLUME2_PROTOCOL *FirmwareVolume2; | |
| Private = FIRMWARE_VOLUME_PRIVATE_DATA_FROM_THIS (This); | |
| FirmwareVolume2 = Private->FirmwareVolume2; | |
| return FirmwareVolume2->ReadSection ( | |
| FirmwareVolume2, | |
| NameGuid, | |
| SectionType, | |
| SectionInstance, | |
| Buffer, | |
| BufferSize, | |
| AuthenticationStatus | |
| ); | |
| } | |
| /** | |
| Write the supplied file (NameGuid) to the FV. | |
| @param This Calling context | |
| @param NumberOfFiles Indicates the number of file records pointed to by FileData | |
| @param WritePolicy Indicates the level of reliability of the write with respect to | |
| things like power failure events. | |
| @param FileData A pointer to an array of EFI_FV_WRITE_FILE_DATA structures. Each | |
| element in the array indicates a file to write, and there are | |
| NumberOfFiles elements in the input array. | |
| @retval EFI_SUCCESS The write completed successfully. | |
| @retval EFI_OUT_OF_RESOURCES The firmware volume does not have enough free space to store file(s). | |
| @retval EFI_DEVICE_ERROR A hardware error occurred when attempting to access the firmware volume. | |
| @retval EFI_WRITE_PROTECTED The firmware volume is configured to disallow writes. | |
| @retval EFI_NOT_FOUND A delete was requested, but the requested file was not | |
| found in the firmware volume. | |
| @retval EFI_INVALID_PARAMETER A delete was requested with a multiple file write. | |
| An unsupported WritePolicy was requested. | |
| An unknown file type was specified. | |
| A file system specific error has occurred. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| FvWriteFile ( | |
| IN EFI_FIRMWARE_VOLUME_PROTOCOL *This, | |
| IN UINT32 NumberOfFiles, | |
| IN FRAMEWORK_EFI_FV_WRITE_POLICY WritePolicy, | |
| IN FRAMEWORK_EFI_FV_WRITE_FILE_DATA *FileData | |
| ) | |
| { | |
| FIRMWARE_VOLUME_PRIVATE_DATA *Private; | |
| EFI_FIRMWARE_VOLUME2_PROTOCOL *FirmwareVolume2; | |
| EFI_FV_WRITE_FILE_DATA *PiFileData; | |
| EFI_STATUS Status; | |
| UINTN Index; | |
| Private = FIRMWARE_VOLUME_PRIVATE_DATA_FROM_THIS (This); | |
| FirmwareVolume2 = Private->FirmwareVolume2; | |
| PiFileData = AllocateCopyPool (sizeof (EFI_FV_WRITE_FILE_DATA), FileData); | |
| ASSERT (PiFileData != NULL); | |
| // | |
| // Framework Spec assume firmware files are Memory-Mapped. | |
| // | |
| for (Index = 0; Index < NumberOfFiles; Index++) { | |
| PiFileData[Index].FileAttributes |= EFI_FV_FILE_ATTRIB_MEMORY_MAPPED; | |
| } | |
| Status = FirmwareVolume2->WriteFile ( | |
| FirmwareVolume2, | |
| NumberOfFiles, | |
| WritePolicy, | |
| (EFI_FV_WRITE_FILE_DATA *)FileData | |
| ); | |
| FreePool (PiFileData); | |
| return Status; | |
| } | |
| /** | |
| Given the input key, search for the next matching file in the volume. | |
| @param This Calling context | |
| @param Key Pointer to a caller allocated buffer that contains an implementation | |
| specific key that is used to track where to begin searching on | |
| successive calls. | |
| @param FileType Indicates the file type to filter for | |
| @param NameGuid Guid filename of the file found | |
| @param Attributes Attributes of the file found | |
| @param Size Size in bytes of the file found | |
| @retval EFI_SUCCESS The output parameters are filled with data obtained from | |
| the first matching file that was found. | |
| @retval EFI_NOT_FOUND No files of type FileType were found. | |
| @retval EFI_DEVICE_ERROR A hardware error occurred when attempting to access | |
| the firmware volume. | |
| @retval EFI_ACCESS_DENIED The firmware volume is configured to disallow reads. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| FvGetNextFile ( | |
| IN EFI_FIRMWARE_VOLUME_PROTOCOL *This, | |
| IN OUT VOID *Key, | |
| IN OUT EFI_FV_FILETYPE *FileType, | |
| OUT EFI_GUID *NameGuid, | |
| OUT EFI_FV_FILE_ATTRIBUTES *Attributes, | |
| OUT UINTN *Size | |
| ) | |
| { | |
| FIRMWARE_VOLUME_PRIVATE_DATA *Private; | |
| EFI_FIRMWARE_VOLUME2_PROTOCOL *FirmwareVolume2; | |
| EFI_STATUS Status; | |
| Private = FIRMWARE_VOLUME_PRIVATE_DATA_FROM_THIS (This); | |
| FirmwareVolume2 = Private->FirmwareVolume2; | |
| Status = FirmwareVolume2->GetNextFile ( | |
| FirmwareVolume2, | |
| Key, | |
| FileType, | |
| NameGuid, | |
| Attributes, | |
| Size | |
| ); | |
| // | |
| // For Framework FV attrbutes, only alignment fields are valid. | |
| // | |
| *Attributes = *Attributes & EFI_FV_FILE_ATTRIB_ALIGNMENT; | |
| return Status; | |
| } | |
| // | |
| // Firmware Volume Protocol template | |
| // | |
| EFI_EVENT mFvRegistration; | |
| FIRMWARE_VOLUME_PRIVATE_DATA gFirmwareVolumePrivateDataTemplate = { | |
| FIRMWARE_VOLUME_PRIVATE_DATA_SIGNATURE, | |
| { | |
| FvGetVolumeAttributes, | |
| FvSetVolumeAttributes, | |
| FvReadFile, | |
| FvReadSection, | |
| FvWriteFile, | |
| FvGetNextFile, | |
| 0, | |
| NULL | |
| }, | |
| NULL | |
| }; | |
| // | |
| // Module globals | |
| // | |
| /** | |
| This notification function is invoked when an instance of the | |
| EFI_FIRMWARE_VOLUME2_PROTOCOL is produced. It installs another instance of the | |
| EFI_FIRMWARE_VOLUME_PROTOCOL on the same handle. | |
| @param Event The event that occured | |
| @param Context Context of event. Not used in this nofication function. | |
| **/ | |
| VOID | |
| EFIAPI | |
| FvNotificationEvent ( | |
| IN EFI_EVENT Event, | |
| IN VOID *Context | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| UINTN BufferSize; | |
| EFI_HANDLE Handle; | |
| FIRMWARE_VOLUME_PRIVATE_DATA *Private; | |
| EFI_FIRMWARE_VOLUME_PROTOCOL *FirmwareVolume; | |
| while (TRUE) { | |
| BufferSize = sizeof (Handle); | |
| Status = gBS->LocateHandle ( | |
| ByRegisterNotify, | |
| &gEfiFirmwareVolume2ProtocolGuid, | |
| mFvRegistration, | |
| &BufferSize, | |
| &Handle | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| // | |
| // Exit Path of While Loop.... | |
| // | |
| break; | |
| } | |
| // | |
| // Skip this handle if the Firmware Volume Protocol is already installed | |
| // | |
| Status = gBS->HandleProtocol ( | |
| Handle, | |
| &gEfiFirmwareVolumeProtocolGuid, | |
| (VOID **)&FirmwareVolume | |
| ); | |
| if (!EFI_ERROR (Status)) { | |
| continue; | |
| } | |
| // | |
| // Allocate private data structure | |
| // | |
| Private = AllocateCopyPool (sizeof (FIRMWARE_VOLUME_PRIVATE_DATA), &gFirmwareVolumePrivateDataTemplate); | |
| if (Private == NULL) { | |
| continue; | |
| } | |
| // | |
| // Retrieve the Firmware Volume2 Protocol | |
| // | |
| Status = gBS->HandleProtocol ( | |
| Handle, | |
| &gEfiFirmwareVolume2ProtocolGuid, | |
| (VOID **)&Private->FirmwareVolume2 | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| // | |
| // Fill in rest of private data structure | |
| // | |
| Private->FirmwareVolume.KeySize = Private->FirmwareVolume2->KeySize; | |
| Private->FirmwareVolume.ParentHandle = Private->FirmwareVolume2->ParentHandle; | |
| // | |
| // Install Firmware Volume Protocol onto same handle | |
| // | |
| Status = gBS->InstallMultipleProtocolInterfaces ( | |
| &Handle, | |
| &gEfiFirmwareVolumeProtocolGuid, | |
| &Private->FirmwareVolume, | |
| NULL | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| } | |
| } | |
| /** | |
| The user Entry Point for DXE driver. The user code starts with this function | |
| as the real entry point for the image goes into a library that calls this | |
| function. | |
| @param[in] ImageHandle The firmware allocated handle for the EFI image. | |
| @param[in] SystemTable A pointer to the EFI System Table. | |
| @retval EFI_SUCCESS The entry point is executed successfully. | |
| @retval other Some error occurs when executing this entry point. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| InitializeFirmwareVolume2 ( | |
| IN EFI_HANDLE ImageHandle, | |
| IN EFI_SYSTEM_TABLE *SystemTable | |
| ) | |
| { | |
| EfiCreateProtocolNotifyEvent ( | |
| &gEfiFirmwareVolume2ProtocolGuid, | |
| TPL_CALLBACK, | |
| FvNotificationEvent, | |
| NULL, | |
| &mFvRegistration | |
| ); | |
| return EFI_SUCCESS; | |
| } |