Thanks, Martin & Jackman I will review it and get back to you if I have feedback.
Thanks Feng -----Original Message----- From: Olivier Martin [mailto:olivier.mar...@arm.com] Sent: Tuesday, March 25, 2014 04:23 To: Tian, Feng Cc: edk2-devel@lists.sourceforge.net; Brendan Jackman Subject: [PATCH 2/3] MdeModulePkg: Implement EFI_FILE_PROTOCOL over Firmware Volumes From: Brendan Jackman <brendan.jack...@arm.com> This module implements Simple FileSystem protocol over Firmware Volume (FV). EFI Modules included into a FV can be listed and launched from the EFI Shell or any other EFI applications. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Brendan Jackman <brendan.jack...@arm.com> Reviewed-by: Olivier Martin <olivier.mar...@arm.com> --- MdeModulePkg/MdeModulePkg.dsc | 2 + .../FvSimpleFilesystemDxe/FvSimpleFilesystem.c | 536 +++++++++++++++++++++ .../FvSimpleFilesystemDxe.inf | 52 ++ .../FvSimpleFilesystemEntryPoint.c | 405 ++++++++++++++++ .../FvSimpleFilesystemInternal.h | 99 ++++ 5 files changed, 1094 insertions(+) create mode 100644 MdeModulePkg/Universal/FvSimpleFilesystemDxe/FvSimpleFilesystem.c create mode 100644 MdeModulePkg/Universal/FvSimpleFilesystemDxe/FvSimpleFilesystemDxe.inf create mode 100644 MdeModulePkg/Universal/FvSimpleFilesystemDxe/FvSimpleFilesystemEntryPoint.c create mode 100644 MdeModulePkg/Universal/FvSimpleFilesystemDxe/FvSimpleFilesystemInternal.h diff --git a/MdeModulePkg/MdeModulePkg.dsc b/MdeModulePkg/MdeModulePkg.dsc index f473325..363e6c9 100644 --- a/MdeModulePkg/MdeModulePkg.dsc +++ b/MdeModulePkg/MdeModulePkg.dsc @@ -322,6 +322,8 @@ MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableDxe/FirmwarePerformanceDxe.inf MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/BootGraphicsResourceTableDxe.inf + + MdeModulePkg/Universal/FvSimpleFilesystemDxe/FvSimpleFilesystemDxe.inf + [Components.IA32, Components.X64, Components.IPF] MdeModulePkg/Universal/Network/UefiPxeBcDxe/UefiPxeBcDxe.inf MdeModulePkg/Universal/DebugSupportDxe/DebugSupportDxe.inf diff --git a/MdeModulePkg/Universal/FvSimpleFilesystemDxe/FvSimpleFilesystem.c b/MdeModulePkg/Universal/FvSimpleFilesystemDxe/FvSimpleFilesystem.c new file mode 100644 index 0000000..197526c --- /dev/null +++ b/MdeModulePkg/Universal/FvSimpleFilesystemDxe/FvSimpleFilesystem.c @@ -0,0 +1,536 @@ +/** @file +* +* Copyright (c) 2014, ARM Limited. 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. +* +**/ + +/* + A driver using the EFI_FIRMWARE_VOLUME2_PROTOCOL to expose files in +firmware + volumes via the the EFI_SIMPLE_FILESYSTEM_PROTOCOL and EFI_FILE_PROTOCOL. + + Its primary intended use is to be able to start EFI applications + embedded in FVs from the UEFI shell. For this reason, it is not fully + compliant as a filesystem driver: it is entirely read-only, and does + not support partially reading files. + + It will expose a single directory, containing one file for each file + in the firmware volume. If a file has a UI section, its contents will + be used as a filename. Otherwise, a string representation of the GUID will be used. + Files of an executable type (That is PEIM, DRIVER, + COMBINED_PEIM_DRIVER and APPLICATION) will have ".efi" added to their filename. + + The data returned by Read() depends on the type of the underlying FV file: + - For executable types, the first section found that contains executable code + is returned. + - For files of type FREEFORM, the driver attempts to return the first section + of type RAW. If none is found, the entire contents of the FV file are + returned. + - On all other files the entire contents of the FV file is returned, as by + EFI_FIRMWARE_VOLUME2_PROTOCOL.ReadFile. + + See the EFI Firmware Volume specification (a separate document from +the main + UEFI specification) for more information about firmware volumes. +*/ + +#include <PiDxe.h> + +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/DebugLib.h> +#include <Library/PathLib.h> + +#include <Protocol/DriverBinding.h> +#include <Protocol/FirmwareVolume2.h> +#include <Protocol/SimpleFileSystem.h> +#include <Protocol/UnicodeCollation.h> + +#include <Guid/FileSystemInfo.h> +#include <Guid/FileInfo.h> + +#include "FvSimpleFilesystemInternal.h" + +/* + Find and call ReadSection on the first section found of an executable type. +*/ +STATIC +EFI_STATUS +FvFsFindExecutableSection ( + IN FV_FILESYSTEM_FILE *File, + OUT UINTN *BufferSize, + OUT VOID **Buffer + ) +{ + EFI_SECTION_TYPE SectionType; + UINT32 AuthenticationStatus; + EFI_FIRMWARE_VOLUME2_PROTOCOL *FvProtocol; + EFI_STATUS Status; + + FvProtocol = File->Instance->FvProtocol; + + for (SectionType = EFI_SECTION_PE32; SectionType <= EFI_SECTION_TE; SectionType++) { + Status = FvProtocol->ReadSection ( + FvProtocol, + &File->NameGuid, + SectionType, + 0, + Buffer, + BufferSize, + &AuthenticationStatus + ); + if (Status != EFI_NOT_FOUND) { + return Status; + } + } + return EFI_NOT_FOUND; +} + +/* + Get the size of the buffer that will be returned by FvFsReadFile. +*/ +EFI_STATUS +FvFsGetFileSize ( + IN FV_FILESYSTEM_FILE *File, + OUT UINTN *Size + ) +{ + EFI_FIRMWARE_VOLUME2_PROTOCOL *FvProtocol; + UINT32 AuthenticationStatus; + EFI_FV_FILETYPE FoundType; + EFI_FV_FILE_ATTRIBUTES Attributes; + EFI_STATUS Status; + UINT8 IgnoredByte; + VOID *IgnoredPtr; + + FvProtocol = File->Instance->FvProtocol; + + // To get the size of a section, we pass 0 for BufferSize. But we + can't pass // NULL for Buffer, as that will cause a return of + INVALID_PARAMETER, and we // can't pass NULL for *Buffer, as that + will cause the callee to allocate // a buffer of the sections size. + IgnoredPtr = &IgnoredByte; + *Size = 0; + + if (FV_FILETYPE_IS_EXECUTABLE (File->Type)) { + // Get the size of the first executable section out of the file. + Status = FvFsFindExecutableSection (File, Size, &IgnoredPtr); + if (Status == EFI_WARN_BUFFER_TOO_SMALL) { + return EFI_SUCCESS; + } + } else if (File->Type == EFI_FV_FILETYPE_FREEFORM) { + // Try to get the size of a raw section out of the file + Status = FvProtocol->ReadSection ( + FvProtocol, + &File->NameGuid, + EFI_SECTION_RAW, + 0, + &IgnoredPtr, + Size, + &AuthenticationStatus + ); + if (Status == EFI_WARN_BUFFER_TOO_SMALL) { + return EFI_SUCCESS; + } + if (EFI_ERROR (Status)) { + // Didn't find a raw section, just return the whole file's size. + return FvProtocol->ReadFile ( + FvProtocol, + &File->NameGuid, + NULL, + Size, + &FoundType, + &Attributes, + &AuthenticationStatus + ); + } + } else { + // Get the size of the entire file + return FvProtocol->ReadFile ( + FvProtocol, + &File->NameGuid, + NULL, + Size, + &FoundType, + &Attributes, + &AuthenticationStatus + ); + } + + return Status; +} + +/* + Helper function to read a file. See comment at the top of this file +for + information on behaviour. +*/ +EFI_STATUS +FvFsReadFile ( + FV_FILESYSTEM_FILE *File, + UINTN *BufferSize, + VOID **Buffer + ) +{ + EFI_FIRMWARE_VOLUME2_PROTOCOL *FvProtocol; + UINT32 AuthenticationStatus; + EFI_FV_FILETYPE FoundType; + EFI_FV_FILE_ATTRIBUTES Attributes; + EFI_STATUS Status; + + FvProtocol = File->Instance->FvProtocol; + + if (FV_FILETYPE_IS_EXECUTABLE (File->Type)) { + // Read the first executable section out of the file. + Status = FvFsFindExecutableSection (File, BufferSize, Buffer); } + else if (File->Type == EFI_FV_FILETYPE_FREEFORM) { + // Try to read a raw section out of the file + Status = FvProtocol->ReadSection ( + FvProtocol, + &File->NameGuid, + EFI_SECTION_RAW, + 0, + Buffer, + BufferSize, + &AuthenticationStatus + ); + if (EFI_ERROR (Status)) { + // Didn't find a raw section, just return the whole file. + Status = FvProtocol->ReadFile ( + FvProtocol, + &File->NameGuid, + Buffer, + BufferSize, + &FoundType, + &Attributes, + &AuthenticationStatus + ); + } + } else { + // Read the entire file + Status = FvProtocol->ReadFile ( + FvProtocol, + &File->NameGuid, + Buffer, + BufferSize, + &FoundType, + &Attributes, + &AuthenticationStatus + ); + } + + return Status; +} + +/* + Helper function for populating an EFI_FILE_INFO for a file. +*/ +STATIC +EFI_STATUS +FvFsGetFileInfo ( + IN FV_FILESYSTEM_FILE *File, + IN OUT UINTN *BufferSize, + OUT EFI_FILE_INFO *FileInfo + ) +{ + UINTN InfoSize; + + InfoSize = sizeof (EFI_FILE_INFO) + StrSize (File->Name) - sizeof + (CHAR16); if (*BufferSize < InfoSize) { + *BufferSize = InfoSize; + return EFI_BUFFER_TOO_SMALL; + } + + // Initialize FileInfo + ZeroMem (FileInfo, InfoSize); + FileInfo->Size = InfoSize; + FileInfo->Attribute = EFI_FILE_READ_ONLY; + + // File is a directory if it is root. + if (File == File->Instance->Root) { + FileInfo->Attribute |= EFI_FILE_DIRECTORY; } + + FileInfo->FileSize = File->Size; + FileInfo->PhysicalSize = File->Size; + + StrCpy (FileInfo->FileName, File->Name); + + *BufferSize = InfoSize; + return EFI_SUCCESS; +} + +EFIAPI +EFI_STATUS +FvSimpleFilesystemOpen ( + IN EFI_FILE_PROTOCOL *This, + OUT EFI_FILE_PROTOCOL **NewHandle, + IN CHAR16 *FileName, + IN UINT64 OpenMode, + IN UINT64 Attributes + ) +{ + FV_FILESYSTEM_INSTANCE *Instance; + FV_FILESYSTEM_FILE *File; + LIST_ENTRY *FileLink; + + File = FVFS_FILE_FROM_FILE_THIS (This); Instance = File->Instance; + + FileName = PathCleanUpDirectories (FileName); + + if (FileName[0] == L'\\') { + FileName++; + } + + // Check for opening root + if (StrCmp (FileName, L".") == 0 || StrCmp (FileName, L"") == 0) { + *NewHandle = &Instance->Root->FileProtocol; + return EFI_SUCCESS; + } + + // + // Do a linear search for a file in the FV with a matching filename + // for (FileLink = GetFirstNode (&Instance->Files); + !IsNull (&Instance->Files, FileLink); + FileLink = GetNextNode (&Instance->Files, FileLink)) { + + File = FVFS_FILE_FROM_LINK (FileLink); + if (mUnicodeCollation->StriColl (mUnicodeCollation, File->Name, FileName) == 0) { + *NewHandle = &File->FileProtocol; + return EFI_SUCCESS; + } + } + return EFI_NOT_FOUND; +} + +EFIAPI +EFI_STATUS +FvSimpleFilesystemClose ( + IN EFI_FILE_PROTOCOL *This + ) +{ + return EFI_SUCCESS; +} + +/* + Implementation of EFI_FILE_PROTOCOL.Read. + + This implementation is not compliant with the UEFI specification. As +this + driver's only intended use case is for loading and executing EFI +images, + it does not support partial reads. If *BufferSize is less than the +size of the + image being read, it will return EFI_UNSUPPORTED. +*/ +EFIAPI +EFI_STATUS +FvSimpleFilesystemRead ( + IN EFI_FILE_PROTOCOL *This, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ) +{ + FV_FILESYSTEM_INSTANCE *Instance; + FV_FILESYSTEM_FILE *File; + EFI_STATUS Status; + LIST_ENTRY *FileLink; + + File = FVFS_FILE_FROM_FILE_THIS (This); Instance = File->Instance; + + if (File == Instance->Root) { + if (File->DirReadNext) { + // + // Directory read: populate Buffer with an EFI_FILE_INFO + // + Status = FvFsGetFileInfo (File->DirReadNext, BufferSize, Buffer); + if (!EFI_ERROR (Status)) { + // + // Successfully read a directory entry, now update the pointer to the + // next file, which will be read on the next call to this function + // + + FileLink = GetNextNode (&Instance->Files, &File->DirReadNext->Link); + if (IsNull (&Instance->Files, FileLink)) { + // No more files left + File->DirReadNext = NULL; + } else { + File->DirReadNext = FVFS_FILE_FROM_LINK (FileLink); + } + } + return Status; + } else { + // + // Directory read. All entries have been read, so return a zero-size + // buffer. + // + *BufferSize = 0; + return EFI_SUCCESS; + } + } else { + if (*BufferSize < File->Size) { + DEBUG ((EFI_D_ERROR, "FV Filesystem does not support partial file reads\n", *BufferSize, File->Size)); + return EFI_UNSUPPORTED; + } + return FvFsReadFile (File, BufferSize, &Buffer); + } +} + +EFIAPI +EFI_STATUS +FvSimpleFilesystemWrite ( + IN EFI_FILE_PROTOCOL *This, + IN OUT UINTN *BufferSize, + IN VOID *Buffer + ) +{ + return EFI_UNSUPPORTED; +} + + +EFIAPI +EFI_STATUS +FvSimpleFilesystemGetPosition ( + IN EFI_FILE_PROTOCOL *This, + OUT UINT64 *Position + ) +{ + return EFI_UNSUPPORTED; +} + +/* + This implementation of EFI_FILE_PROTOCOL.SetPosition is not compliant +with + the UEFI specification. We do not support partial file reads (see +comment on + FvSimpleFilesystemRead), therefore we only support seeking to +position 0 */ EFIAPI EFI_STATUS FvSimpleFilesystemSetPosition ( + IN EFI_FILE_PROTOCOL *This, + IN UINT64 Position + ) +{ + FV_FILESYSTEM_INSTANCE *Instance; + FV_FILESYSTEM_FILE *File; + + File = FVFS_FILE_FROM_FILE_THIS (This); Instance = File->Instance; + + if (File == Instance->Root) { + if (Position != 0) { + return EFI_INVALID_PARAMETER; + } + // Reset directory position to first entry + File->DirReadNext = FVFS_GET_FIRST_FILE (Instance); } else if + (Position != 0) { + // We don't support partial file reads, so we don't support seeking either. + return EFI_UNSUPPORTED; + } + + return EFI_SUCCESS; +} + +EFIAPI +EFI_STATUS +FvSimpleFilesystemFlush ( + IN EFI_FILE_PROTOCOL *This + ) +{ + return EFI_SUCCESS; +} + +EFIAPI +EFI_STATUS +FvSimpleFilesystemDelete ( + IN EFI_FILE_PROTOCOL *This + ) +{ + return EFI_UNSUPPORTED; +} + +STATIC EFI_FILE_SYSTEM_INFO mFsInfoTemplate = { + 0, // Populate at runtime + TRUE, // Read-only + 0, // Don't know volume size + 0, // No free space + 0, // Don't know block size + L"" // Populate at runtime +}; + +EFIAPI +EFI_STATUS +FvSimpleFilesystemGetInfo ( + IN EFI_FILE_PROTOCOL *This, + IN EFI_GUID *InformationType, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ) +{ + FV_FILESYSTEM_FILE *File; + EFI_FILE_SYSTEM_INFO *FsInfoOut; + FV_FILESYSTEM_INSTANCE *Instance; + UINTN InfoSize; + + File = FVFS_FILE_FROM_FILE_THIS (This); + + if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) { + // + // Return filesystem info + // + Instance = File->Instance; + + InfoSize = sizeof (EFI_FILE_SYSTEM_INFO) + StrSize (Instance->VolumeLabel) + - sizeof (CHAR16); + + if (*BufferSize < InfoSize) { + *BufferSize = InfoSize; + return EFI_BUFFER_TOO_SMALL; + } + + // Cast output buffer for convenience + FsInfoOut = (EFI_FILE_SYSTEM_INFO *) Buffer; + + CopyMem (FsInfoOut, &mFsInfoTemplate, mFsInfoTemplate.Size); + StrCpy (FsInfoOut->VolumeLabel, Instance->VolumeLabel); + return EFI_SUCCESS; + } else if (CompareGuid (InformationType, &gEfiFileInfoGuid)) { + // + // Return file info + // + + return FvFsGetFileInfo (File, BufferSize, (EFI_FILE_INFO *) +Buffer); + } else { + return EFI_UNSUPPORTED; + } +} + +EFIAPI +EFI_STATUS +FvSimpleFilesystemSetInfo ( + IN EFI_FILE_PROTOCOL *This, + IN EFI_GUID *InformationType, + IN UINTN BufferSize, + IN VOID *Buffer + ) +{ + return EFI_UNSUPPORTED; +} + +EFI_FILE_PROTOCOL mFilesystemTemplate = { + EFI_FILE_PROTOCOL_REVISION, + FvSimpleFilesystemOpen, + FvSimpleFilesystemClose, + FvSimpleFilesystemDelete, + FvSimpleFilesystemRead, + FvSimpleFilesystemWrite, + FvSimpleFilesystemGetPosition, + FvSimpleFilesystemSetPosition, + FvSimpleFilesystemGetInfo, + FvSimpleFilesystemSetInfo, + FvSimpleFilesystemFlush +}; diff --git a/MdeModulePkg/Universal/FvSimpleFilesystemDxe/FvSimpleFilesystemDxe.inf b/MdeModulePkg/Universal/FvSimpleFilesystemDxe/FvSimpleFilesystemDxe.inf new file mode 100644 index 0000000..9d42004 --- /dev/null +++ b/MdeModulePkg/Universal/FvSimpleFilesystemDxe/FvSimpleFilesystemDxe +++ .inf @@ -0,0 +1,52 @@ +#/** @file +# Support for Simple File System over Firmware Volume # # Copyright +(c) 2014, ARM Ltd. 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. +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = FvSimpleFilesystem + FILE_GUID = 907125c0-a5f1-11e3-a3fe-a3198b49350c + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = FvSimpleFilesystemEntryPoint + +[Sources] + FvSimpleFilesystem.c + FvSimpleFilesystemEntryPoint.c + FvSimpleFilesystemInternal.h + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + BaseLib + DevicePathLib + MemoryAllocationLib + PathLib + PrintLib + UefiDriverEntryPoint + +[Guids] + gEfiFileInfoGuid + gEfiFileSystemInfoGuid + gEfiFileSystemVolumeLabelInfoIdGuid + +[Protocols] + gEfiDevicePathFromTextProtocolGuid + gEfiDevicePathProtocolGuid + gEfiDriverBindingProtocolGuid + gEfiFirmwareVolume2ProtocolGuid + gEfiSimpleFileSystemProtocolGuid + gEfiUnicodeCollationProtocolGuid diff --git a/MdeModulePkg/Universal/FvSimpleFilesystemDxe/FvSimpleFilesystemEntryPoint.c b/MdeModulePkg/Universal/FvSimpleFilesystemDxe/FvSimpleFilesystemEntryPoint.c new file mode 100644 index 0000000..0b286db --- /dev/null +++ b/MdeModulePkg/Universal/FvSimpleFilesystemDxe/FvSimpleFilesystemEnt +++ ryPoint.c @@ -0,0 +1,405 @@ +/** @file +* +* Copyright (c) 2014, ARM Limited. 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. +* +**/ + +#include <PiDxe.h> + +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/DebugLib.h> +#include <Library/DevicePathLib.h> +#include <Library/MemoryAllocationLib.h> #include <Library/PrintLib.h> +#include <Library/UefiBootServicesTableLib.h> + +#include <Protocol/DriverBinding.h> +#include <Protocol/FirmwareVolume2.h> +#include <Protocol/SimpleFileSystem.h> +#include <Protocol/UnicodeCollation.h> + +#include "FvSimpleFilesystemInternal.h" + +EFI_UNICODE_COLLATION_PROTOCOL *mUnicodeCollation = NULL; + +// A Guid string is 32 hex characters with 4 hyphens: 36 characters +total #define GUID_STRING_SIZE (36 * sizeof (CHAR16)) + +#define FVFS_VOLUME_LABEL_PREFIX L"Firmware Volume: " +#define FVFS_VOLUME_LABEL_SIZE (sizeof (FVFS_VOLUME_LABEL_PREFIX) + GUID_STRING_SIZE) +#define FVFS_FALLBACK_VOLUME_LABEL L"Firmware Volume" + +EFI_STATUS +EFIAPI +FvSimpleFilesystemOpenVolume ( + IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This, + OUT EFI_FILE_PROTOCOL **RootFile + ) +{ + EFI_STATUS Status; + FV_FILESYSTEM_FILE *Root; + CHAR16 *UiSection; + EFI_GUID NameGuid; + EFI_FV_FILE_ATTRIBUTES Attributes; + UINT32 Authentication; + VOID *Key; + EFI_FV_FILETYPE FileType; + UINTN Size; + FV_FILESYSTEM_INSTANCE *Instance; + FV_FILESYSTEM_FILE *File; + EFI_FIRMWARE_VOLUME2_PROTOCOL *FvProtocol; + CHAR16 *Name; + UINTN NumChars; + + Instance = FVFS_INSTANCE_FROM_SIMPLE_FS_THIS (This); Status = + EFI_SUCCESS; + + if (Instance->Root == NULL) { + // + // Allocate file structure for root file + // + Root = AllocatePool (sizeof (FV_FILESYSTEM_FILE)); + if (Root == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Instance->Root = Root; + + Root->Instance = Instance; + Root->Signature = FVFS_FILE_SIGNATURE; + Root->Name = L""; + Root->Size = 0; + CopyMem (&Root->FileProtocol, &mFilesystemTemplate, sizeof + (mFilesystemTemplate)); + + // + // Populate the instance's list of files. We consider anything a file that + // has a UI_SECTION, which we consider to be its filename. + // + + FvProtocol = Instance->FvProtocol; + + // Allocate Key + Key = AllocatePool (FvProtocol->KeySize); + ASSERT (Key != NULL); + ZeroMem (Key, FvProtocol->KeySize); + + do { + FileType = EFI_FV_FILETYPE_ALL; + + Status = FvProtocol->GetNextFile ( + FvProtocol, + Key, + &FileType, + &NameGuid, + &Attributes, + &Size + ); + if (EFI_ERROR (Status)) { + ASSERT (Status == EFI_NOT_FOUND); + break; + } + + // + // Found a file. + // Allocate a file structure and populate it. + // + File = AllocatePool (sizeof (FV_FILESYSTEM_FILE)); + if (File == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Get a file's name: If it has a UI section, use that, otherwise use + // its NameGuid. + // + + UiSection = NULL; + Status = FvProtocol->ReadSection ( + FvProtocol, + &NameGuid, + EFI_SECTION_USER_INTERFACE, + 0, + (VOID **)&UiSection, + &Size, + &Authentication + ); + if (!EFI_ERROR (Status)) { + Name = UiSection; + } else { + Name = AllocatePool (GUID_STRING_SIZE); + if (Name == NULL) { + return EFI_OUT_OF_RESOURCES; + } + NumChars = UnicodeSPrint (Name, GUID_STRING_SIZE, L"%g", &NameGuid); + ASSERT (NumChars == GUID_STRING_SIZE); + } + + // Add ".efi" to filenames of drivers and applications. + if (FV_FILETYPE_IS_EXECUTABLE (FileType)) { + File->Name = AllocateCopyPool (StrSize (Name) + 8, Name); + StrCat (File->Name, L".efi"); + FreePool (Name); + } else { + File->Name = Name; + } + + File->Type = FileType; + File->Signature = FVFS_FILE_SIGNATURE; + CopyGuid (&File->NameGuid, &NameGuid); + File->Instance = Instance; + CopyMem (&File->FileProtocol, &mFilesystemTemplate, sizeof (mFilesystemTemplate)); + InsertHeadList (&Instance->Files, &File->Link); + + // Call FvFsReadFile to get the file's size + File->Size = 0; + Status = FvFsGetFileSize (File, &File->Size); + ASSERT_EFI_ERROR (Status); + } while (TRUE); + + FreePool (Key); + + if (Status == EFI_NOT_FOUND) { + Status = EFI_SUCCESS; + } + } + + Instance->Root->DirReadNext = FVFS_GET_FIRST_FILE (Instance); + *RootFile = &Instance->Root->FileProtocol; + return Status; +} + +STATIC EFI_SIMPLE_FILE_SYSTEM_PROTOCOL mSimpleFsTemplate = { + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION, + FvSimpleFilesystemOpenVolume +}; + +EFI_STATUS +EFIAPI +FvSimpleFilesystemDriverSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *DriverBinding, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath OPTIONAL + ) +{ + return gBS->OpenProtocol ( + ControllerHandle, + &gEfiFirmwareVolume2ProtocolGuid, + NULL, + gImageHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); +} + +EFI_STATUS +EFIAPI +FvSimpleFilesystemDriverStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *DriverBinding, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath OPTIONAL + ) +{ + EFI_STATUS Status; + EFI_FIRMWARE_VOLUME2_PROTOCOL *FvProtocol; + FV_FILESYSTEM_INSTANCE *Instance; + EFI_DEVICE_PATH_PROTOCOL *FvDevicePath; + EFI_GUID *FvGuid; + UINTN NumChars; + + Status = gBS->LocateProtocol ( + &gEfiUnicodeCollationProtocolGuid, + NULL, + (VOID **) &mUnicodeCollation + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Open FV protocol + // + + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiFirmwareVolume2ProtocolGuid, + (VOID **) &FvProtocol, + gImageHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Create an instance + // + Instance = AllocatePool (sizeof (FV_FILESYSTEM_INSTANCE)); if + (Instance == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Instance->Root = NULL; + Instance->FvProtocol = FvProtocol; + Instance->Signature = FVFS_INSTANCE_SIGNATURE; InitializeListHead + (&Instance->Files); CopyMem (&Instance->SimpleFs, &mSimpleFsTemplate, + sizeof (mSimpleFsTemplate)); + + Status = gBS->InstallProtocolInterface( + &ControllerHandle, + &gEfiSimpleFileSystemProtocolGuid, + EFI_NATIVE_INTERFACE, + &Instance->SimpleFs + ); + + // + // Decide on a filesystem volume label, which will include the FV's guid. + // + + // Get the device path to find the FV's GUID Instance->VolumeLabel = + NULL; Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiDevicePathProtocolGuid, + (VOID **) &FvDevicePath, + gImageHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (!EFI_ERROR (Status)) { + // Iterate over device path until we find a firmware volume node + while (!IsDevicePathEndType (FvDevicePath)) { + if (DevicePathType (FvDevicePath) == MEDIA_DEVICE_PATH && + DevicePathSubType (FvDevicePath) == MEDIA_PIWG_FW_VOL_DP) { + // Allocate the volume label + Instance->VolumeLabel = AllocatePool (FVFS_VOLUME_LABEL_SIZE); + // Check the allocation was successful + if (Instance->VolumeLabel != NULL) { + // Extract the FV's guid + FvGuid = &((MEDIA_FW_VOL_DEVICE_PATH *) FvDevicePath)->FvName; + // Build the volume label string + NumChars = UnicodeSPrint ( + Instance->VolumeLabel, + FVFS_VOLUME_LABEL_SIZE, + FVFS_VOLUME_LABEL_PREFIX L"%g", + FvGuid + ); + ASSERT (NumChars == FVFS_VOLUME_LABEL_SIZE); + } + break; + } + FvDevicePath = NextDevicePathNode (FvDevicePath); + } + } + // If we didn't decide on a volume label, set a fallback one if + (Instance->VolumeLabel == NULL) { + Instance->VolumeLabel = AllocateCopyPool ( + sizeof (FVFS_FALLBACK_VOLUME_LABEL), + FVFS_FALLBACK_VOLUME_LABEL + ); + } + + return Status; +} + +EFI_STATUS +EFIAPI +FvSimpleFilesystemDriverStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *DriverBinding, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer OPTIONAL + ) +{ + EFI_STATUS Status; + FV_FILESYSTEM_INSTANCE *Instance; + FV_FILESYSTEM_FILE *File; + LIST_ENTRY *FileLink; + + Instance = FVFS_INSTANCE_FROM_BINDING_THIS (DriverBinding); + + // + // Close and uninstall protocols. + // + + Status = gBS->CloseProtocol ( + ControllerHandle, + &gEfiFirmwareVolume2ProtocolGuid, + gImageHandle, + ControllerHandle + ); + ASSERT_EFI_ERROR (Status); + + Status = gBS->UninstallProtocolInterface ( + ControllerHandle, + &gEfiSimpleFileSystemProtocolGuid, + &Instance->SimpleFs + ); + ASSERT_EFI_ERROR (Status); + + // + // Free file structures + // + + if (Instance->Root != NULL) { + for (FileLink = GetFirstNode (&Instance->Files); + !IsNull (&Instance->Files, FileLink); + FileLink = GetNextNode (&Instance->Files, FileLink)) { + File = FVFS_FILE_FROM_LINK (FileLink); + + FreePool (File->Name); + FreePool (File); + } + // Root->Name is statically allocated, no need to free. + FreePool (Instance->Root); + } + + // + // Free Instance + // + + if (Instance->VolumeLabel != NULL) { + FreePool (Instance->VolumeLabel); + } + FreePool (Instance); + + return EFI_SUCCESS; +} + +EFI_DRIVER_BINDING_PROTOCOL mDriverBinding = { + FvSimpleFilesystemDriverSupported, + FvSimpleFilesystemDriverStart, + FvSimpleFilesystemDriverStop, + 0, + NULL, + NULL +}; + +EFIAPI +EFI_STATUS +FvSimpleFilesystemEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + Status = gBS->InstallProtocolInterface ( + &ImageHandle, + &gEfiDriverBindingProtocolGuid, + EFI_NATIVE_INTERFACE, + &mDriverBinding + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} diff --git a/MdeModulePkg/Universal/FvSimpleFilesystemDxe/FvSimpleFilesystemInternal.h b/MdeModulePkg/Universal/FvSimpleFilesystemDxe/FvSimpleFilesystemInternal.h new file mode 100644 index 0000000..ecf5461 --- /dev/null +++ b/MdeModulePkg/Universal/FvSimpleFilesystemDxe/FvSimpleFilesystemInt +++ ernal.h @@ -0,0 +1,99 @@ +/** @file +* +* Copyright (c) 2014, ARM Limited. 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. +* +**/ + +#ifndef __FVFS_INTERNAL_H__ +#define __FVFS_INTERNAL_H__ + +#include <Library/BaseLib.h> + +typedef struct _FV_FILESYSTEM_FILE FV_FILESYSTEM_FILE; + +// Struct representing an instance of the "filesystem". There will be +one of // these structs per FV. +typedef struct _FV_FILESYSTEM_INSTANCE { + UINT32 Signature; + LIST_ENTRY Link; + LIST_ENTRY Files; + EFI_DRIVER_BINDING_PROTOCOL *DriverBinding; + EFI_FIRMWARE_VOLUME2_PROTOCOL *FvProtocol; + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL SimpleFs; + FV_FILESYSTEM_FILE *Root; + CHAR16 *VolumeLabel; +} FV_FILESYSTEM_INSTANCE; + +// Struct representing a file. There will be one of these for each file +on each // FV, plus one for each FV representing the "root directory". +struct _FV_FILESYSTEM_FILE { + UINT32 Signature; + LIST_ENTRY Link; + CHAR16 *Name; + FV_FILESYSTEM_FILE *DirReadNext; + EFI_GUID NameGuid; + FV_FILESYSTEM_INSTANCE *Instance; + EFI_FILE_PROTOCOL FileProtocol; + UINTN Size; + EFI_FV_FILETYPE Type; +}; + +#define FVFS_FILE_SIGNATURE SIGNATURE_32 ('f', 'v', 'f', 'l') +#define FVFS_INSTANCE_SIGNATURE SIGNATURE_32 ('f', 'v', 'f', 's') + +#define FVFS_INSTANCE_FROM_BINDING_THIS(This) CR ( \ + This, \ + FV_FILESYSTEM_INSTANCE, \ + DriverBinding, \ + FVFS_INSTANCE_SIGNATURE \ + ) + +#define FVFS_INSTANCE_FROM_SIMPLE_FS_THIS(This) CR ( \ + This, \ + FV_FILESYSTEM_INSTANCE, \ + SimpleFs, \ + FVFS_INSTANCE_SIGNATURE \ + ) + +#define FVFS_FILE_FROM_FILE_THIS(This) CR ( \ + This, \ + FV_FILESYSTEM_FILE, \ + FileProtocol, \ + FVFS_FILE_SIGNATURE \ + ) + +#define FVFS_FILE_FROM_LINK(FileLink) CR (FileLink, FV_FILESYSTEM_FILE, +Link, FVFS_FILE_SIGNATURE) + +#define FVFS_GET_FIRST_FILE(Instance) FVFS_FILE_FROM_LINK (GetFirstNode +(&Instance->Files)) + +#define FV_FILETYPE_IS_EXECUTABLE(Type) ((Type) == EFI_FV_FILETYPE_PEIM || \ + (Type) == EFI_FV_FILETYPE_DRIVER || \ + (Type) == EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER || \ + (Type) == +EFI_FV_FILETYPE_APPLICATION) + +EFI_STATUS +FvFsReadFile ( + FV_FILESYSTEM_FILE *File, + UINTN *BufferSize, + VOID **Buffer + ); + +EFI_STATUS +FvFsGetFileSize ( + IN FV_FILESYSTEM_FILE *File, + OUT UINTN *Size + ); + +extern EFI_FILE_PROTOCOL mFilesystemTemplate; + +extern EFI_UNICODE_COLLATION_PROTOCOL *mUnicodeCollation; + +#endif -- 1.8.5 ------------------------------------------------------------------------------ Learn Graph Databases - Download FREE O'Reilly Book "Graph Databases" is the definitive new guide to graph databases and their applications. Written by three acclaimed leaders in the field, this first edition is now available. Download your free book today! http://p.sf.net/sfu/13534_NeoTech _______________________________________________ edk2-devel mailing list edk2-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/edk2-devel