| /*++ | |
| 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; | |
| } | |