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

Reply via email to