/*++ | |
Copyright (c) 2006, 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: | |
FwVolRead.c | |
Abstract: | |
Implements read firmware file | |
--*/ | |
#include <DxeMain.h> | |
/*++ | |
Required Alignment Alignment Value in FFS Alignment Value in | |
(bytes) Attributes Field Firmware Volume Interfaces | |
1 0 0 | |
2 0 1 | |
4 0 2 | |
8 0 3 | |
16 1 4 | |
128 2 7 | |
512 3 9 | |
1 KB 4 10 | |
4 KB 5 12 | |
32 KB 6 15 | |
64 KB 7 16 | |
--*/ | |
UINT8 mFvAttributes[] = {0, 4, 7, 9, 10, 12, 15, 16}; | |
STATIC | |
EFI_FV_FILE_ATTRIBUTES | |
FfsAttributes2FvFileAttributes ( | |
IN EFI_FFS_FILE_ATTRIBUTES FfsAttributes | |
) | |
/*++ | |
Routine Description: | |
Convert the FFS File Attributes to FV File Attributes | |
Arguments: | |
FfsAttributes - The attributes of UINT8 type. | |
Returns: | |
The attributes of EFI_FV_FILE_ATTRIBUTES | |
--*/ | |
{ | |
FfsAttributes = (EFI_FFS_FILE_ATTRIBUTES)((FfsAttributes & FFS_ATTRIB_DATA_ALIGNMENT) >> 3); | |
ASSERT (FfsAttributes < 8); | |
return (EFI_FV_FILE_ATTRIBUTES) mFvAttributes[FfsAttributes]; | |
} | |
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 | |
) | |
/*++ | |
Routine Description: | |
Given the input key, search for the next matching file in the volume. | |
Arguments: | |
This - Indicates the calling context. | |
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. | |
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(). | |
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. | |
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. | |
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. | |
Returns: | |
EFI_SUCCESS - Successfully find the file. | |
EFI_DEVICE_ERROR - Device error. | |
EFI_ACCESS_DENIED - Fv could not read. | |
EFI_NOT_FOUND - No matching file found. | |
EFI_INVALID_PARAMETER - Invalid parameter | |
--*/ | |
{ | |
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 = FvGetVolumeAttributes (This, &FvAttributes); | |
if (EFI_ERROR (Status)){ | |
return Status; | |
} | |
// | |
// Check if read operation is enabled | |
// | |
if ((FvAttributes & EFI_FV_READ_STATUS) == 0) { | |
return EFI_ACCESS_DENIED; | |
} | |
if (*FileType > EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) { | |
// | |
// File type needs to be in 0 - 0x0B | |
// | |
return EFI_INVALID_PARAMETER; | |
} | |
KeyValue = (UINTN *)Key; | |
for (;;) { | |
if (*KeyValue == 0) { | |
// | |
// Search for 1st matching file | |
// | |
Link = &FvDevice->FfsFileListHeader; | |
} else { | |
// | |
// Key is pointer to FFsFileEntry, so get next one | |
// | |
Link = (LIST_ENTRY *)(*KeyValue); | |
} | |
if (Link->ForwardLink == &FvDevice->FfsFileListHeader) { | |
// | |
// Next is end of list so we did not find data | |
// | |
return EFI_NOT_FOUND; | |
} | |
FfsFileEntry = (FFS_FILE_LIST_ENTRY *)Link->ForwardLink; | |
FfsFileHeader = (EFI_FFS_FILE_HEADER *)FfsFileEntry->FfsHeader; | |
// | |
// remember the key | |
// | |
*KeyValue = (UINTN)FfsFileEntry; | |
if (FfsFileHeader->Type == EFI_FV_FILETYPE_FFS_PAD) { | |
// | |
// we ignore pad files | |
// | |
continue; | |
} | |
if (*FileType == 0) { | |
// | |
// Process all file types so we have a match | |
// | |
break; | |
} | |
if (*FileType == FfsFileHeader->Type) { | |
// | |
// Found a matching file type | |
// | |
break; | |
} | |
} | |
// | |
// Return FileType, NameGuid, and Attributes | |
// | |
*FileType = FfsFileHeader->Type; | |
CopyMem (NameGuid, &FfsFileHeader->Name, sizeof (EFI_GUID)); | |
*Attributes = FfsAttributes2FvFileAttributes (FfsFileHeader->Attributes); | |
// | |
// Read four bytes out of the 3 byte array and throw out extra data | |
// | |
FileLength = *(UINT32 *)&FfsFileHeader->Size[0] & 0x00FFFFFF; | |
// | |
// we need to substract the header size | |
// | |
*Size = FileLength - sizeof(EFI_FFS_FILE_HEADER); | |
if (FfsFileHeader->Attributes & FFS_ATTRIB_TAIL_PRESENT) { | |
// | |
// If tail is present substract it's size; | |
// | |
*Size -= sizeof(EFI_FFS_FILE_TAIL); | |
} | |
return EFI_SUCCESS; | |
} | |
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 | |
) | |
/*++ | |
Routine Description: | |
Locates a file in the firmware volume and | |
copies it to the supplied buffer. | |
Arguments: | |
This - Indicates the calling context. | |
NameGuid - Pointer to an EFI_GUID, which is the filename. | |
Buffer - Buffer is a pointer to pointer to a buffer in | |
which the file or section contents or are returned. | |
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. | |
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. | |
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. | |
AuthenticationStatus - AuthenticationStatus is a pointer to a caller | |
allocated UINTN in which the authentication status | |
is returned. | |
Returns: | |
EFI_SUCCESS - Successfully read to memory buffer. | |
EFI_WARN_BUFFER_TOO_SMALL - Buffer too small. | |
EFI_NOT_FOUND - Not found. | |
EFI_DEVICE_ERROR - Device error. | |
EFI_ACCESS_DENIED - Could not read. | |
EFI_INVALID_PARAMETER - Invalid parameter. | |
EFI_OUT_OF_RESOURCES - Not enough buffer to be allocated. | |
--*/ | |
{ | |
EFI_STATUS Status; | |
FV_DEVICE *FvDevice; | |
EFI_GUID SearchNameGuid; | |
EFI_FV_FILETYPE LocalFoundType; | |
EFI_FV_FILE_ATTRIBUTES LocalAttributes; | |
UINTN FileSize; | |
UINT8 *SrcPtr; | |
EFI_FFS_FILE_HEADER *FfsHeader; | |
UINTN InputBufferSize; | |
if (NULL == NameGuid) { | |
return EFI_INVALID_PARAMETER; | |
} | |
FvDevice = FV_DEVICE_FROM_THIS (This); | |
// | |
// Keep looking until we find the matching NameGuid. | |
// The Key is really an FfsFileEntry | |
// | |
FvDevice->LastKey = 0; | |
do { | |
LocalFoundType = 0; | |
Status = FvGetNextFile ( | |
This, | |
&FvDevice->LastKey, | |
&LocalFoundType, | |
&SearchNameGuid, | |
&LocalAttributes, | |
&FileSize | |
); | |
if (EFI_ERROR (Status)) { | |
return EFI_NOT_FOUND; | |
} | |
} while (!CompareGuid (&SearchNameGuid, NameGuid)); | |
// | |
// Get a pointer to the header | |
// | |
FfsHeader = FvDevice->LastKey->FfsHeader; | |
// | |
// Remember callers buffer size | |
// | |
InputBufferSize = *BufferSize; | |
// | |
// Calculate return values | |
// | |
*FoundType = FfsHeader->Type; | |
*FileAttributes = FfsAttributes2FvFileAttributes (FfsHeader->Attributes); | |
*AuthenticationStatus = 0; | |
*BufferSize = FileSize; | |
if (Buffer == NULL) { | |
// | |
// If Buffer is NULL, we only want to get the information colected so far | |
// | |
return EFI_SUCCESS; | |
} | |
// | |
// Skip over file header | |
// | |
SrcPtr = ((UINT8 *)FfsHeader) + sizeof (EFI_FFS_FILE_HEADER); | |
Status = EFI_SUCCESS; | |
if (*Buffer == NULL) { | |
// | |
// Caller passed in a pointer so allocate buffer for them | |
// | |
*Buffer = CoreAllocateBootServicesPool (FileSize); | |
if (*Buffer == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
} else if (FileSize > InputBufferSize) { | |
// | |
// Callers buffer was not big enough | |
// | |
Status = EFI_WARN_BUFFER_TOO_SMALL; | |
FileSize = InputBufferSize; | |
} | |
// | |
// Copy data into callers buffer | |
// | |
CopyMem (*Buffer, SrcPtr, FileSize); | |
return Status; | |
} | |
EFI_STATUS | |
EFIAPI | |
FvReadFileSection ( | |
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 | |
) | |
/*++ | |
Routine Description: | |
Locates a section in a given FFS File and | |
copies it to the supplied buffer (not including section header). | |
Arguments: | |
This - Indicates the calling context. | |
NameGuid - Pointer to an EFI_GUID, which is the filename. | |
SectionType - Indicates the section type to return. | |
SectionInstance - Indicates which instance of sections with a type of | |
SectionType to return. | |
Buffer - Buffer is a pointer to pointer to a buffer in which | |
the file or section contents or are returned. | |
BufferSize - BufferSize is a pointer to caller allocated UINTN. | |
AuthenticationStatus -AuthenticationStatus is a pointer to a caller | |
allocated UINT32 in which the authentication status | |
is returned. | |
Returns: | |
EFI_SUCCESS - Successfully read the file section into buffer. | |
EFI_WARN_BUFFER_TOO_SMALL - Buffer too small. | |
EFI_NOT_FOUND - Section not found. | |
EFI_DEVICE_ERROR - Device error. | |
EFI_ACCESS_DENIED - Could not read. | |
EFI_INVALID_PARAMETER - Invalid parameter. | |
--*/ | |
{ | |
EFI_STATUS Status; | |
FV_DEVICE *FvDevice; | |
EFI_FV_FILETYPE FileType; | |
EFI_FV_FILE_ATTRIBUTES FileAttributes; | |
UINTN FileSize; | |
UINT8 *FileBuffer; | |
EFI_SECTION_EXTRACTION_PROTOCOL *Sep; | |
FFS_FILE_LIST_ENTRY *FfsEntry; | |
if (NULL == NameGuid || Buffer == NULL) { | |
return EFI_INVALID_PARAMETER; | |
} | |
FvDevice = FV_DEVICE_FROM_THIS (This); | |
// | |
// Read the whole file into buffer | |
// | |
FileBuffer = NULL; | |
Status = FvReadFile ( | |
This, | |
NameGuid, | |
(VOID **)&FileBuffer, | |
&FileSize, | |
&FileType, | |
&FileAttributes, | |
AuthenticationStatus | |
); | |
// | |
// Get the last key used by our call to FvReadFile as it is the FfsEntry for this file. | |
// | |
FfsEntry = (FFS_FILE_LIST_ENTRY *)FvDevice->LastKey; | |
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) { | |
Status = EFI_NOT_FOUND; | |
goto Done; | |
} | |
// | |
// Use FfsEntry to cache Section Extraction Protocol Inforomation | |
// | |
if (FfsEntry->StreamHandle == 0) { | |
// | |
// Located the protocol | |
// | |
Status = CoreLocateProtocol (&gEfiSectionExtractionProtocolGuid, NULL, (VOID **)&Sep); | |
// | |
// Section Extraction Protocol is part of Dxe Core so this should never fail | |
// | |
ASSERT_EFI_ERROR (Status); | |
Status = Sep->OpenSectionStream ( | |
Sep, | |
FileSize, | |
FileBuffer, | |
&FfsEntry->StreamHandle | |
); | |
if (EFI_ERROR (Status)) { | |
goto Done; | |
} | |
FfsEntry->Sep = Sep; | |
} else { | |
// | |
// Get cached copy of Sep | |
// | |
Sep = FfsEntry->Sep; | |
} | |
// | |
// If SectionType == 0 We need the whole section stream | |
// | |
Status = Sep->GetSection ( | |
Sep, | |
FfsEntry->StreamHandle, | |
(SectionType == 0) ? NULL : &SectionType, | |
NULL, | |
(SectionType == 0) ? 0 : SectionInstance, | |
Buffer, | |
BufferSize, | |
AuthenticationStatus | |
); | |
// | |
// Close of stream defered to close of FfsHeader list to allow SEP to cache data | |
// | |
Done: | |
CoreFreePool (FileBuffer); | |
return Status; | |
} | |