IntelFrameworkModulePkg: Add FwVolDxe driver
Signed-off-by: jljusten Reviewed-by: rsun3 Reviewed-by: lgao4 git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@12256 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
@ -0,0 +1,580 @@
|
||||
/** @file
|
||||
Implements functions to read firmware file.
|
||||
|
||||
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.
|
||||
|
||||
**/
|
||||
|
||||
#include "FwVolDriver.h"
|
||||
|
||||
UINT8 mFvAttributes[] = { 0, 4, 7, 9, 10, 12, 15, 16 };
|
||||
|
||||
/**
|
||||
Convert the FFS File Attributes to FV File Attributes.
|
||||
|
||||
@param FfsAttributes The attributes of UINT8 type.
|
||||
|
||||
@return The attributes of EFI_FV_FILE_ATTRIBUTES
|
||||
|
||||
**/
|
||||
EFI_FV_FILE_ATTRIBUTES
|
||||
FfsAttributes2FvFileAttributes (
|
||||
IN EFI_FFS_FILE_ATTRIBUTES FfsAttributes
|
||||
)
|
||||
{
|
||||
FfsAttributes = (EFI_FFS_FILE_ATTRIBUTES) ((FfsAttributes & FFS_ATTRIB_DATA_ALIGNMENT) >> 3);
|
||||
ASSERT (FfsAttributes < 8);
|
||||
return (EFI_FV_FILE_ATTRIBUTES) mFvAttributes[FfsAttributes];
|
||||
}
|
||||
|
||||
/**
|
||||
Given the input key, search for the next matching file in the volume.
|
||||
|
||||
@param This Indicates the calling context.
|
||||
@param Key Key is a pointer to a caller allocated
|
||||
buffer that contains implementation specific
|
||||
data that is used to track where to begin
|
||||
the search for the next file. The size of
|
||||
the buffer must be at least This->KeySize
|
||||
bytes long. To reinitialize the search and
|
||||
begin from the beginning of the firmware
|
||||
volume, the entire buffer must be cleared to
|
||||
zero. Other than clearing the buffer to
|
||||
initiate a new search, the caller must not
|
||||
modify the data in the buffer between calls
|
||||
to GetNextFile().
|
||||
@param FileType FileType is a pointer to a caller allocated
|
||||
EFI_FV_FILETYPE. The GetNextFile() API can
|
||||
filter it's search for files based on the
|
||||
value of *FileType input. A *FileType input
|
||||
of 0 causes GetNextFile() to search for
|
||||
files of all types. If a file is found, the
|
||||
file's type is returned in *FileType.
|
||||
*FileType is not modified if no file is
|
||||
found.
|
||||
@param NameGuid NameGuid is a pointer to a caller allocated
|
||||
EFI_GUID. If a file is found, the file's
|
||||
name is returned in *NameGuid. *NameGuid is
|
||||
not modified if no file is found.
|
||||
@param Attributes Attributes is a pointer to a caller
|
||||
allocated EFI_FV_FILE_ATTRIBUTES. If a file
|
||||
is found, the file's attributes are returned
|
||||
in *Attributes. *Attributes is not modified
|
||||
if no file is found.
|
||||
@param Size Size is a pointer to a caller allocated
|
||||
UINTN. If a file is found, the file's size
|
||||
is returned in *Size. *Size is not modified
|
||||
if no file is found.
|
||||
|
||||
@retval EFI_SUCCESS Successfully find the file.
|
||||
@retval EFI_DEVICE_ERROR Device error.
|
||||
@retval EFI_ACCESS_DENIED Fv could not read.
|
||||
@retval EFI_NOT_FOUND No matching file found.
|
||||
@retval EFI_INVALID_PARAMETER Invalid parameter
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
FvGetNextFile (
|
||||
IN CONST EFI_FIRMWARE_VOLUME2_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
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
FV_DEVICE *FvDevice;
|
||||
EFI_FV_ATTRIBUTES FvAttributes;
|
||||
EFI_FFS_FILE_HEADER *FfsFileHeader;
|
||||
UINTN *KeyValue;
|
||||
LIST_ENTRY *Link;
|
||||
FFS_FILE_LIST_ENTRY *FfsFileEntry;
|
||||
UINTN FileLength;
|
||||
|
||||
FvDevice = FV_DEVICE_FROM_THIS (This);
|
||||
|
||||
Status = This->GetVolumeAttributes (This, &FvAttributes);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
KeyValue = (UINTN *) Key;
|
||||
FfsFileHeader = NULL;
|
||||
|
||||
//
|
||||
// Check if read operation is enabled
|
||||
//
|
||||
if ((FvAttributes & EFI_FV2_READ_STATUS) == 0) {
|
||||
return EFI_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
if (*FileType > EFI_FV_FILETYPE_SMM_CORE) {
|
||||
//
|
||||
// File type needs to be in 0 - 0x0D
|
||||
//
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
|
||||
do {
|
||||
if (*KeyValue == 0) {
|
||||
//
|
||||
// Search for 1st matching file
|
||||
//
|
||||
Link = &FvDevice->FfsFileListHeader;
|
||||
if (Link->ForwardLink == &FvDevice->FfsFileListHeader) {
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
|
||||
FfsFileEntry = (FFS_FILE_LIST_ENTRY *) Link->ForwardLink;
|
||||
FfsFileHeader = (EFI_FFS_FILE_HEADER *) FfsFileEntry->FfsHeader;
|
||||
|
||||
//
|
||||
// remember the key
|
||||
//
|
||||
*KeyValue = (UINTN) FfsFileEntry;
|
||||
|
||||
//
|
||||
// we ignore pad files
|
||||
//
|
||||
if (FfsFileHeader->Type == EFI_FV_FILETYPE_FFS_PAD) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (*FileType == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (*FileType == FfsFileHeader->Type) {
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
//
|
||||
// Getting link from last Ffs
|
||||
//
|
||||
Link = (LIST_ENTRY *) (*KeyValue);
|
||||
if (Link->ForwardLink == &FvDevice->FfsFileListHeader) {
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
|
||||
FfsFileEntry = (FFS_FILE_LIST_ENTRY *) Link->ForwardLink;
|
||||
FfsFileHeader = (EFI_FFS_FILE_HEADER *) FfsFileEntry->FfsHeader;
|
||||
|
||||
//
|
||||
// remember the key
|
||||
//
|
||||
*KeyValue = (UINTN) FfsFileEntry;
|
||||
|
||||
//
|
||||
// we ignore pad files
|
||||
//
|
||||
if (FfsFileHeader->Type == EFI_FV_FILETYPE_FFS_PAD) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (*FileType == EFI_FV_FILETYPE_ALL) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (*FileType == FfsFileHeader->Type) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (Link->ForwardLink != &FvDevice->FfsFileListHeader);
|
||||
|
||||
//
|
||||
// Cache this file entry
|
||||
//
|
||||
FvDevice->CurrentFfsFile = FfsFileEntry;
|
||||
|
||||
*FileType = FfsFileHeader->Type;
|
||||
CopyGuid (NameGuid, &FfsFileHeader->Name);
|
||||
*Attributes = FfsAttributes2FvFileAttributes (FfsFileHeader->Attributes);
|
||||
|
||||
FileLength = *(UINT32 *) FfsFileHeader->Size & 0x00FFFFFF;
|
||||
|
||||
//
|
||||
// we need to substract the header size
|
||||
//
|
||||
*Size = FileLength - sizeof (EFI_FFS_FILE_HEADER);
|
||||
|
||||
if (CompareGuid (&gEfiFirmwareVolumeTopFileGuid, NameGuid)) {
|
||||
//
|
||||
// specially deal with VTF file
|
||||
//
|
||||
UINT8 *SrcPtr;
|
||||
UINT32 Tmp;
|
||||
|
||||
SrcPtr = (UINT8 *) FfsFileHeader;
|
||||
SrcPtr += sizeof (EFI_FFS_FILE_HEADER);
|
||||
|
||||
while (*Size >= 4) {
|
||||
Tmp = *(UINT32 *) SrcPtr;
|
||||
if (Tmp == 0) {
|
||||
SrcPtr += 4;
|
||||
(*Size) -= 4;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
Locates a file in the firmware volume and
|
||||
copies it to the supplied buffer.
|
||||
|
||||
@param This Indicates the calling context.
|
||||
@param NameGuid Pointer to an EFI_GUID, which is the
|
||||
filename.
|
||||
@param Buffer Buffer is a pointer to pointer to a buffer
|
||||
in which the file or section contents or are
|
||||
returned.
|
||||
@param BufferSize BufferSize is a pointer to caller allocated
|
||||
UINTN. On input *BufferSize indicates the
|
||||
size in bytes of the memory region pointed
|
||||
to by Buffer. On output, *BufferSize
|
||||
contains the number of bytes required to
|
||||
read the file.
|
||||
@param FoundType FoundType is a pointer to a caller allocated
|
||||
EFI_FV_FILETYPE that on successful return
|
||||
from Read() contains the type of file read.
|
||||
This output reflects the file type
|
||||
irrespective of the value of the SectionType
|
||||
input.
|
||||
@param FileAttributes FileAttributes is a pointer to a caller
|
||||
allocated EFI_FV_FILE_ATTRIBUTES. On
|
||||
successful return from Read(),
|
||||
*FileAttributes contains the attributes of
|
||||
the file read.
|
||||
@param AuthenticationStatus AuthenticationStatus is a pointer to a
|
||||
caller allocated UINTN in which the
|
||||
authentication status is returned.
|
||||
|
||||
@retval EFI_SUCCESS Successfully read to memory buffer.
|
||||
@retval EFI_WARN_BUFFER_TOO_SMALL Buffer too small.
|
||||
@retval EFI_NOT_FOUND Not found.
|
||||
@retval EFI_DEVICE_ERROR Device error.
|
||||
@retval EFI_ACCESS_DENIED Could not read.
|
||||
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
||||
@retval EFI_OUT_OF_RESOURCES Not enough buffer to be allocated.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
FvReadFile (
|
||||
IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
|
||||
IN CONST 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
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
FV_DEVICE *FvDevice;
|
||||
UINTN Key;
|
||||
EFI_GUID SearchNameGuid;
|
||||
EFI_FV_ATTRIBUTES FvAttributes;
|
||||
EFI_FV_FILETYPE LocalFoundType;
|
||||
EFI_FV_FILE_ATTRIBUTES LocalAttributes;
|
||||
UINTN FileSize;
|
||||
UINT8 *SrcPtr;
|
||||
FFS_FILE_LIST_ENTRY *FfsFileEntry;
|
||||
EFI_FFS_FILE_HEADER *FfsHeader;
|
||||
UINT8 *FileBuffer;
|
||||
|
||||
if (NULL == This || NULL == NameGuid) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
FvDevice = FV_DEVICE_FROM_THIS (This);
|
||||
|
||||
Status = This->GetVolumeAttributes (This, &FvAttributes);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
//
|
||||
// First check to see that FV is enabled for reads...
|
||||
//
|
||||
if (0 == (FvAttributes & EFI_FV2_READ_STATUS)) {
|
||||
return EFI_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
FfsHeader = NULL;
|
||||
|
||||
//
|
||||
// Check if the file was read last time.
|
||||
//
|
||||
FfsFileEntry = FvDevice->CurrentFfsFile;
|
||||
|
||||
if (FfsFileEntry != NULL) {
|
||||
FfsHeader = (EFI_FFS_FILE_HEADER *) FfsFileEntry->FfsHeader;
|
||||
}
|
||||
|
||||
if ((FfsFileEntry == NULL) || (!CompareGuid (&FfsHeader->Name, NameGuid))) {
|
||||
//
|
||||
// If not match or no file cached, search this file
|
||||
//
|
||||
Key = 0;
|
||||
do {
|
||||
LocalFoundType = 0;
|
||||
Status = This->GetNextFile (
|
||||
This,
|
||||
&Key,
|
||||
&LocalFoundType,
|
||||
&SearchNameGuid,
|
||||
&LocalAttributes,
|
||||
&FileSize
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
} while (!CompareGuid (&SearchNameGuid, NameGuid));
|
||||
|
||||
//
|
||||
// Get file entry
|
||||
//
|
||||
FfsFileEntry = (FFS_FILE_LIST_ENTRY *) Key;
|
||||
|
||||
//
|
||||
// Update the cache
|
||||
//
|
||||
FvDevice->CurrentFfsFile = FfsFileEntry;
|
||||
|
||||
FfsHeader = (EFI_FFS_FILE_HEADER *) FfsFileEntry->FfsHeader;
|
||||
|
||||
} else {
|
||||
//
|
||||
// Get File Size of the cached file
|
||||
//
|
||||
FileSize = *(UINT32 *) FfsHeader->Size & 0x00FFFFFF;
|
||||
FileSize -= sizeof (EFI_FFS_FILE_HEADER);
|
||||
}
|
||||
//
|
||||
// Get file info
|
||||
//
|
||||
*FoundType = FfsHeader->Type;
|
||||
*FileAttributes = FfsAttributes2FvFileAttributes (FfsHeader->Attributes);
|
||||
*AuthenticationStatus = 0;
|
||||
|
||||
//
|
||||
// If Buffer is NULL, we only want to get some information
|
||||
//
|
||||
if (Buffer == NULL) {
|
||||
*BufferSize = FileSize;
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
SrcPtr = (UINT8 *) FfsHeader;
|
||||
SrcPtr += sizeof (EFI_FFS_FILE_HEADER);
|
||||
|
||||
if (CompareGuid (&gEfiFirmwareVolumeTopFileGuid, NameGuid)) {
|
||||
//
|
||||
// specially deal with VTF file
|
||||
//
|
||||
UINT32 Tmp;
|
||||
|
||||
while (FileSize >= 4) {
|
||||
Tmp = *(UINT32 *) SrcPtr;
|
||||
if (Tmp == 0) {
|
||||
SrcPtr += 4;
|
||||
FileSize -= 4;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
//
|
||||
// If we drop out of the above loop, we've found the correct file header...
|
||||
//
|
||||
if (*Buffer == NULL) {
|
||||
FileBuffer = AllocateCopyPool (FileSize, SrcPtr);
|
||||
if (FileBuffer == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
*BufferSize = FileSize;
|
||||
*Buffer = FileBuffer;
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
//
|
||||
// If the user's buffer is smaller than the file size, then copy as much
|
||||
// as we can and return an appropriate status.
|
||||
//
|
||||
if (FileSize > *BufferSize) {
|
||||
CopyMem (*Buffer, SrcPtr, *BufferSize);
|
||||
*BufferSize = FileSize;
|
||||
return EFI_WARN_BUFFER_TOO_SMALL;
|
||||
}
|
||||
//
|
||||
// User's buffer size is ok, so copy the entire file to their buffer.
|
||||
//
|
||||
*BufferSize = FileSize;
|
||||
CopyMem (*Buffer, SrcPtr, *BufferSize);
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
Locates a section in a given FFS File and
|
||||
copies it to the supplied buffer (not including section header).
|
||||
|
||||
@param This Indicates the calling context.
|
||||
@param NameGuid Pointer to an EFI_GUID, which is the
|
||||
filename.
|
||||
@param SectionType Indicates the section type to return.
|
||||
@param SectionInstance Indicates which instance of sections with a
|
||||
type of SectionType to return.
|
||||
@param Buffer Buffer is a pointer to pointer to a buffer
|
||||
in which the file or section contents or are
|
||||
returned.
|
||||
@param BufferSize BufferSize is a pointer to caller allocated
|
||||
UINTN.
|
||||
@param AuthenticationStatus AuthenticationStatus is a pointer to a
|
||||
caller allocated UINT32 in which the
|
||||
authentication status is returned.
|
||||
|
||||
@retval EFI_SUCCESS Successfully read the file section into
|
||||
buffer.
|
||||
@retval EFI_WARN_BUFFER_TOO_SMALL Buffer too small.
|
||||
@retval EFI_NOT_FOUND Section not found.
|
||||
@retval EFI_DEVICE_ERROR Device error.
|
||||
@retval EFI_ACCESS_DENIED Could not read.
|
||||
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
FvReadFileSection (
|
||||
IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
|
||||
IN CONST EFI_GUID *NameGuid,
|
||||
IN EFI_SECTION_TYPE SectionType,
|
||||
IN UINTN SectionInstance,
|
||||
IN OUT VOID **Buffer,
|
||||
IN OUT UINTN *BufferSize,
|
||||
OUT UINT32 *AuthenticationStatus
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
EFI_FV_ATTRIBUTES FvAttributes;
|
||||
EFI_FV_FILETYPE FileType;
|
||||
EFI_FV_FILE_ATTRIBUTES FileAttributes;
|
||||
UINTN FileSize;
|
||||
UINT8 *FileBuffer;
|
||||
EFI_SECTION_EXTRACTION_PROTOCOL *Sep;
|
||||
UINTN StreamHandle;
|
||||
|
||||
if (NULL == This || NULL == NameGuid || Buffer == NULL) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
Status = This->GetVolumeAttributes (This, &FvAttributes);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
//
|
||||
// First check to see that FV is enabled for reads...
|
||||
//
|
||||
if (0 == (FvAttributes & EFI_FV2_READ_STATUS)) {
|
||||
return EFI_ACCESS_DENIED;
|
||||
}
|
||||
//
|
||||
// Read the whole file into buffer
|
||||
//
|
||||
FileBuffer = NULL;
|
||||
Status = This->ReadFile (
|
||||
This,
|
||||
NameGuid,
|
||||
(VOID **) &FileBuffer,
|
||||
&FileSize,
|
||||
&FileType,
|
||||
&FileAttributes,
|
||||
AuthenticationStatus
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
//
|
||||
// Check to see that the file actually HAS sections before we go any further.
|
||||
//
|
||||
if (FileType == EFI_FV_FILETYPE_RAW) {
|
||||
FreePool (FileBuffer);
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
//
|
||||
// Located the protocol
|
||||
//
|
||||
Status = gBS->LocateProtocol (
|
||||
&gEfiSectionExtractionProtocolGuid,
|
||||
NULL,
|
||||
(VOID **) &Sep
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
FreePool (FileBuffer);
|
||||
return Status;
|
||||
}
|
||||
|
||||
Status = Sep->OpenSectionStream (
|
||||
Sep,
|
||||
FileSize,
|
||||
FileBuffer,
|
||||
&StreamHandle
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
FreePool (FileBuffer);
|
||||
return Status;
|
||||
}
|
||||
|
||||
if (SectionType == 0) {
|
||||
//
|
||||
// We need the whole section stream
|
||||
//
|
||||
Status = Sep->GetSection (
|
||||
Sep,
|
||||
StreamHandle,
|
||||
NULL,
|
||||
NULL,
|
||||
0,
|
||||
Buffer,
|
||||
BufferSize,
|
||||
AuthenticationStatus
|
||||
);
|
||||
} else {
|
||||
Status = Sep->GetSection (
|
||||
Sep,
|
||||
StreamHandle,
|
||||
&SectionType,
|
||||
NULL,
|
||||
SectionInstance,
|
||||
Buffer,
|
||||
BufferSize,
|
||||
AuthenticationStatus
|
||||
);
|
||||
}
|
||||
//
|
||||
// Handle AuthenticationStatus if necessary
|
||||
//
|
||||
Sep->CloseSectionStream (Sep, StreamHandle);
|
||||
|
||||
FreePool (FileBuffer);
|
||||
|
||||
return Status;
|
||||
}
|
Reference in New Issue
Block a user